From 70cb7db9129b7b2bdbb48e3eb8d442fdcc2812e9 Mon Sep 17 00:00:00 2001 From: Milan Date: Mon, 25 Oct 2021 20:08:41 -0400 Subject: [PATCH 1/3] rust: add `to_str` and `as_str_unchecked` to `CStr` Following the `std::ffi::CStr` pattern of `to_str`, this adds methods to convert CStr to &str both safely and unsafely Signed-off-by: Milan Landaverde --- rust/kernel/str.rs | 73 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs index ff5bc12f956802..678825c6b3d7ab 100644 --- a/rust/kernel/str.rs +++ b/rust/kernel/str.rs @@ -167,6 +167,50 @@ impl CStr { pub const fn as_bytes_with_nul(&self) -> &[u8] { &self.0 } + + /// Yields a [`&str`] slice if the `CStr` contains valid UTF-8. + /// + /// If the contents of the `CStr` are valid UTF-8 data, this + /// function will return the corresponding [`&str`] slice. Otherwise, + /// it will return an error with details of where UTF-8 validation failed. + /// + /// # Examples + /// + /// ``` + /// # use kernel::str::CStr; + /// let cstr = CStr::from_bytes_with_nul(b"foo\0").unwrap(); + /// assert_eq!(cstr.to_str(), Ok("foo")); + /// ``` + #[inline] + pub fn to_str(&self) -> Result<&str, core::str::Utf8Error> { + core::str::from_utf8(self.as_bytes()) + } + + /// Unsafely convert this CStr into a `&str`, without checking for + /// valid UTF-8. + /// + /// # Safety + /// + /// Callers *must* ensure that CStr is valid UTF-8 before + /// calling this method. Converting a CStr into a `&str` that is + /// not valid UTF-8 is considered undefined behavior. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # use kernel::c_str; + /// # use kernel::str::CStr; + /// // SAFETY: This is safe because string literals are guaranteed to be + /// // valid UTF-8 by the Rust compiler. + /// let bar = c_str!("ツ"); + /// assert_eq!(unsafe { bar.as_str_unchecked() }, "ツ"); + /// ``` + #[inline] + pub unsafe fn as_str_unchecked(&self) -> &str { + unsafe { core::str::from_utf8_unchecked(self.as_bytes()) } + } } impl AsRef for CStr { @@ -251,3 +295,32 @@ macro_rules! c_str { C }}; } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_cstr_to_str() { + let good_bytes = b"\xf0\x9f\xa6\x80\0"; + let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap(); + let checked_str = checked_cstr.to_str().unwrap(); + assert_eq!(checked_str, "🦀"); + } + + #[test] + #[should_panic] + fn test_cstr_to_str_panic() { + let bad_bytes = b"\xc3\x28\0"; + let unchecked_c_str = unsafe { CStr::from_bytes_with_nul_unchecked(bad_bytes) }; + unchecked_c_str.to_str().unwrap(); + } + + #[test] + fn test_cstr_as_str() { + let good_bytes = b"\xf0\x9f\x90\xA7\0"; + let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap(); + let unchecked_str = unsafe { checked_cstr.as_str_unchecked() }; + assert_eq!(unchecked_str, "🐧"); + } +} From 9fae345b62581c66d05975b4e4a21a8713af6782 Mon Sep 17 00:00:00 2001 From: Milan Date: Thu, 28 Oct 2021 13:05:43 -0400 Subject: [PATCH 2/3] rust: simplify as_str_unchecked doc Co-authored-by: Miguel Ojeda Signed-off-by: Milan Landaverde --- rust/kernel/str.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs index 678825c6b3d7ab..2f4e7c0cb477df 100644 --- a/rust/kernel/str.rs +++ b/rust/kernel/str.rs @@ -191,19 +191,15 @@ impl CStr { /// /// # Safety /// - /// Callers *must* ensure that CStr is valid UTF-8 before - /// calling this method. Converting a CStr into a `&str` that is - /// not valid UTF-8 is considered undefined behavior. + /// The contents must be valid UTF-8. /// /// # Examples /// - /// Basic usage: - /// /// ``` /// # use kernel::c_str; /// # use kernel::str::CStr; - /// // SAFETY: This is safe because string literals are guaranteed to be - /// // valid UTF-8 by the Rust compiler. + /// // SAFETY: String literals are guaranteed to be valid UTF-8 + /// // by the Rust compiler. /// let bar = c_str!("ツ"); /// assert_eq!(unsafe { bar.as_str_unchecked() }, "ツ"); /// ``` From 813e0c1ff173fe88affb02395aa65f8c3f6f7e2d Mon Sep 17 00:00:00 2001 From: Milan L Date: Thu, 28 Oct 2021 13:46:10 -0400 Subject: [PATCH 3/3] rust: intra-doc links & test fixes For to_str & as_str_unchecked Signed-off-by: Milan Landaverde --- rust/kernel/str.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs index 2f4e7c0cb477df..eb7dab1c7c45c9 100644 --- a/rust/kernel/str.rs +++ b/rust/kernel/str.rs @@ -168,9 +168,9 @@ impl CStr { &self.0 } - /// Yields a [`&str`] slice if the `CStr` contains valid UTF-8. + /// Yields a [`&str`] slice if the [`CStr`] contains valid UTF-8. /// - /// If the contents of the `CStr` are valid UTF-8 data, this + /// If the contents of the [`CStr`] are valid UTF-8 data, this /// function will return the corresponding [`&str`] slice. Otherwise, /// it will return an error with details of where UTF-8 validation failed. /// @@ -186,7 +186,7 @@ impl CStr { core::str::from_utf8(self.as_bytes()) } - /// Unsafely convert this CStr into a `&str`, without checking for + /// Unsafely convert this [`CStr`] into a [`&str`], without checking for /// valid UTF-8. /// /// # Safety @@ -308,12 +308,12 @@ mod tests { #[should_panic] fn test_cstr_to_str_panic() { let bad_bytes = b"\xc3\x28\0"; - let unchecked_c_str = unsafe { CStr::from_bytes_with_nul_unchecked(bad_bytes) }; - unchecked_c_str.to_str().unwrap(); + let checked_cstr = CStr::from_bytes_with_nul(bad_bytes).unwrap(); + checked_cstr.to_str().unwrap(); } #[test] - fn test_cstr_as_str() { + fn test_cstr_as_str_unchecked() { let good_bytes = b"\xf0\x9f\x90\xA7\0"; let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap(); let unchecked_str = unsafe { checked_cstr.as_str_unchecked() };