Skip to content

Commit b9ed1ad

Browse files
authored
Merge pull request #533 from mdaverde/ml/cstr
rust: add `to_str` and `as_str_unchecked` to `CStr`
2 parents 597bee0 + 813e0c1 commit b9ed1ad

File tree

1 file changed

+69
-0
lines changed

1 file changed

+69
-0
lines changed

rust/kernel/str.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,46 @@ impl CStr {
167167
pub const fn as_bytes_with_nul(&self) -> &[u8] {
168168
&self.0
169169
}
170+
171+
/// Yields a [`&str`] slice if the [`CStr`] contains valid UTF-8.
172+
///
173+
/// If the contents of the [`CStr`] are valid UTF-8 data, this
174+
/// function will return the corresponding [`&str`] slice. Otherwise,
175+
/// it will return an error with details of where UTF-8 validation failed.
176+
///
177+
/// # Examples
178+
///
179+
/// ```
180+
/// # use kernel::str::CStr;
181+
/// let cstr = CStr::from_bytes_with_nul(b"foo\0").unwrap();
182+
/// assert_eq!(cstr.to_str(), Ok("foo"));
183+
/// ```
184+
#[inline]
185+
pub fn to_str(&self) -> Result<&str, core::str::Utf8Error> {
186+
core::str::from_utf8(self.as_bytes())
187+
}
188+
189+
/// Unsafely convert this [`CStr`] into a [`&str`], without checking for
190+
/// valid UTF-8.
191+
///
192+
/// # Safety
193+
///
194+
/// The contents must be valid UTF-8.
195+
///
196+
/// # Examples
197+
///
198+
/// ```
199+
/// # use kernel::c_str;
200+
/// # use kernel::str::CStr;
201+
/// // SAFETY: String literals are guaranteed to be valid UTF-8
202+
/// // by the Rust compiler.
203+
/// let bar = c_str!("ツ");
204+
/// assert_eq!(unsafe { bar.as_str_unchecked() }, "ツ");
205+
/// ```
206+
#[inline]
207+
pub unsafe fn as_str_unchecked(&self) -> &str {
208+
unsafe { core::str::from_utf8_unchecked(self.as_bytes()) }
209+
}
170210
}
171211

172212
impl AsRef<BStr> for CStr {
@@ -251,3 +291,32 @@ macro_rules! c_str {
251291
C
252292
}};
253293
}
294+
295+
#[cfg(test)]
296+
mod tests {
297+
use super::*;
298+
299+
#[test]
300+
fn test_cstr_to_str() {
301+
let good_bytes = b"\xf0\x9f\xa6\x80\0";
302+
let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap();
303+
let checked_str = checked_cstr.to_str().unwrap();
304+
assert_eq!(checked_str, "🦀");
305+
}
306+
307+
#[test]
308+
#[should_panic]
309+
fn test_cstr_to_str_panic() {
310+
let bad_bytes = b"\xc3\x28\0";
311+
let checked_cstr = CStr::from_bytes_with_nul(bad_bytes).unwrap();
312+
checked_cstr.to_str().unwrap();
313+
}
314+
315+
#[test]
316+
fn test_cstr_as_str_unchecked() {
317+
let good_bytes = b"\xf0\x9f\x90\xA7\0";
318+
let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap();
319+
let unchecked_str = unsafe { checked_cstr.as_str_unchecked() };
320+
assert_eq!(unchecked_str, "🐧");
321+
}
322+
}

0 commit comments

Comments
 (0)