1247b365dSWedson Almeida Filho // SPDX-License-Identifier: GPL-2.0 2247b365dSWedson Almeida Filho 3247b365dSWedson Almeida Filho //! String representations. 4247b365dSWedson Almeida Filho 558eff8e8SDanilo Krummrich use crate::alloc::{flags::*, AllocError, KVec}; 6c07e67bdSGary Guo use core::fmt::{self, Write}; 7a321f3adSDanilo Krummrich use core::ops::{self, Deref, DerefMut, Index}; 8247b365dSWedson Almeida Filho 900280272SMiguel Ojeda use crate::error::{code::*, Error}; 10d126d238SGary Guo 117c597746SGary Guo /// Byte string without UTF-8 validity guarantee. 124951ddd5SYutaro Ohno #[repr(transparent)] 134951ddd5SYutaro Ohno pub struct BStr([u8]); 144951ddd5SYutaro Ohno 154951ddd5SYutaro Ohno impl BStr { 164951ddd5SYutaro Ohno /// Returns the length of this string. 174951ddd5SYutaro Ohno #[inline] len(&self) -> usize184951ddd5SYutaro Ohno pub const fn len(&self) -> usize { 194951ddd5SYutaro Ohno self.0.len() 204951ddd5SYutaro Ohno } 214951ddd5SYutaro Ohno 224951ddd5SYutaro Ohno /// Returns `true` if the string is empty. 234951ddd5SYutaro Ohno #[inline] is_empty(&self) -> bool244951ddd5SYutaro Ohno pub const fn is_empty(&self) -> bool { 254951ddd5SYutaro Ohno self.len() == 0 264951ddd5SYutaro Ohno } 274951ddd5SYutaro Ohno 284951ddd5SYutaro Ohno /// Creates a [`BStr`] from a `[u8]`. 294951ddd5SYutaro Ohno #[inline] from_bytes(bytes: &[u8]) -> &Self304951ddd5SYutaro Ohno pub const fn from_bytes(bytes: &[u8]) -> &Self { 314951ddd5SYutaro Ohno // SAFETY: `BStr` is transparent to `[u8]`. 324951ddd5SYutaro Ohno unsafe { &*(bytes as *const [u8] as *const BStr) } 334951ddd5SYutaro Ohno } 345928642bSAndreas Hindborg 355928642bSAndreas Hindborg /// Strip a prefix from `self`. Delegates to [`slice::strip_prefix`]. 365928642bSAndreas Hindborg /// 375928642bSAndreas Hindborg /// # Examples 385928642bSAndreas Hindborg /// 395928642bSAndreas Hindborg /// ``` 405928642bSAndreas Hindborg /// # use kernel::b_str; 415928642bSAndreas Hindborg /// assert_eq!(Some(b_str!("bar")), b_str!("foobar").strip_prefix(b_str!("foo"))); 425928642bSAndreas Hindborg /// assert_eq!(None, b_str!("foobar").strip_prefix(b_str!("bar"))); 435928642bSAndreas Hindborg /// assert_eq!(Some(b_str!("foobar")), b_str!("foobar").strip_prefix(b_str!(""))); 445928642bSAndreas Hindborg /// assert_eq!(Some(b_str!("")), b_str!("foobar").strip_prefix(b_str!("foobar"))); 455928642bSAndreas Hindborg /// ``` strip_prefix(&self, pattern: impl AsRef<Self>) -> Option<&BStr>465928642bSAndreas Hindborg pub fn strip_prefix(&self, pattern: impl AsRef<Self>) -> Option<&BStr> { 475928642bSAndreas Hindborg self.deref() 485928642bSAndreas Hindborg .strip_prefix(pattern.as_ref().deref()) 495928642bSAndreas Hindborg .map(Self::from_bytes) 505928642bSAndreas Hindborg } 514951ddd5SYutaro Ohno } 524951ddd5SYutaro Ohno 534951ddd5SYutaro Ohno impl fmt::Display for BStr { 544951ddd5SYutaro Ohno /// Formats printable ASCII characters, escaping the rest. 557c597746SGary Guo /// 564951ddd5SYutaro Ohno /// ``` 574951ddd5SYutaro Ohno /// # use kernel::{fmt, b_str, str::{BStr, CString}}; 584951ddd5SYutaro Ohno /// let ascii = b_str!("Hello, BStr!"); 59b6357e26SDaniel Sedlak /// let s = CString::try_from_fmt(fmt!("{}", ascii))?; 604951ddd5SYutaro Ohno /// assert_eq!(s.as_bytes(), "Hello, BStr!".as_bytes()); 614951ddd5SYutaro Ohno /// 624951ddd5SYutaro Ohno /// let non_ascii = b_str!(""); 63b6357e26SDaniel Sedlak /// let s = CString::try_from_fmt(fmt!("{}", non_ascii))?; 644951ddd5SYutaro Ohno /// assert_eq!(s.as_bytes(), "\\xf0\\x9f\\xa6\\x80".as_bytes()); 65b6357e26SDaniel Sedlak /// # Ok::<(), kernel::error::Error>(()) 664951ddd5SYutaro Ohno /// ``` fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result674951ddd5SYutaro Ohno fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 684951ddd5SYutaro Ohno for &b in &self.0 { 694951ddd5SYutaro Ohno match b { 704951ddd5SYutaro Ohno // Common escape codes. 714951ddd5SYutaro Ohno b'\t' => f.write_str("\\t")?, 724951ddd5SYutaro Ohno b'\n' => f.write_str("\\n")?, 734951ddd5SYutaro Ohno b'\r' => f.write_str("\\r")?, 744951ddd5SYutaro Ohno // Printable characters. 754951ddd5SYutaro Ohno 0x20..=0x7e => f.write_char(b as char)?, 76*211dcf77SMiguel Ojeda _ => write!(f, "\\x{b:02x}")?, 774951ddd5SYutaro Ohno } 784951ddd5SYutaro Ohno } 794951ddd5SYutaro Ohno Ok(()) 804951ddd5SYutaro Ohno } 814951ddd5SYutaro Ohno } 824951ddd5SYutaro Ohno 834951ddd5SYutaro Ohno impl fmt::Debug for BStr { 844951ddd5SYutaro Ohno /// Formats printable ASCII characters with a double quote on either end, 854951ddd5SYutaro Ohno /// escaping the rest. 864951ddd5SYutaro Ohno /// 874951ddd5SYutaro Ohno /// ``` 884951ddd5SYutaro Ohno /// # use kernel::{fmt, b_str, str::{BStr, CString}}; 894951ddd5SYutaro Ohno /// // Embedded double quotes are escaped. 904951ddd5SYutaro Ohno /// let ascii = b_str!("Hello, \"BStr\"!"); 91b6357e26SDaniel Sedlak /// let s = CString::try_from_fmt(fmt!("{:?}", ascii))?; 924951ddd5SYutaro Ohno /// assert_eq!(s.as_bytes(), "\"Hello, \\\"BStr\\\"!\"".as_bytes()); 934951ddd5SYutaro Ohno /// 944951ddd5SYutaro Ohno /// let non_ascii = b_str!(""); 95b6357e26SDaniel Sedlak /// let s = CString::try_from_fmt(fmt!("{:?}", non_ascii))?; 964951ddd5SYutaro Ohno /// assert_eq!(s.as_bytes(), "\"\\xf0\\x9f\\x98\\xba\"".as_bytes()); 97b6357e26SDaniel Sedlak /// # Ok::<(), kernel::error::Error>(()) 984951ddd5SYutaro Ohno /// ``` fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result994951ddd5SYutaro Ohno fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1004951ddd5SYutaro Ohno f.write_char('"')?; 1014951ddd5SYutaro Ohno for &b in &self.0 { 1024951ddd5SYutaro Ohno match b { 1034951ddd5SYutaro Ohno // Common escape codes. 1044951ddd5SYutaro Ohno b'\t' => f.write_str("\\t")?, 1054951ddd5SYutaro Ohno b'\n' => f.write_str("\\n")?, 1064951ddd5SYutaro Ohno b'\r' => f.write_str("\\r")?, 1074951ddd5SYutaro Ohno // String escape characters. 1084951ddd5SYutaro Ohno b'\"' => f.write_str("\\\"")?, 1094951ddd5SYutaro Ohno b'\\' => f.write_str("\\\\")?, 1104951ddd5SYutaro Ohno // Printable characters. 1114951ddd5SYutaro Ohno 0x20..=0x7e => f.write_char(b as char)?, 112*211dcf77SMiguel Ojeda _ => write!(f, "\\x{b:02x}")?, 1134951ddd5SYutaro Ohno } 1144951ddd5SYutaro Ohno } 1154951ddd5SYutaro Ohno f.write_char('"') 1164951ddd5SYutaro Ohno } 1174951ddd5SYutaro Ohno } 1184951ddd5SYutaro Ohno 1194951ddd5SYutaro Ohno impl Deref for BStr { 1204951ddd5SYutaro Ohno type Target = [u8]; 1214951ddd5SYutaro Ohno 1224951ddd5SYutaro Ohno #[inline] deref(&self) -> &Self::Target1234951ddd5SYutaro Ohno fn deref(&self) -> &Self::Target { 1244951ddd5SYutaro Ohno &self.0 1254951ddd5SYutaro Ohno } 1264951ddd5SYutaro Ohno } 1277c597746SGary Guo 1283eff946dSAndreas Hindborg impl PartialEq for BStr { eq(&self, other: &Self) -> bool1293eff946dSAndreas Hindborg fn eq(&self, other: &Self) -> bool { 1303eff946dSAndreas Hindborg self.deref().eq(other.deref()) 1313eff946dSAndreas Hindborg } 1323eff946dSAndreas Hindborg } 1333eff946dSAndreas Hindborg 13450a5ff0aSAndreas Hindborg impl<Idx> Index<Idx> for BStr 13550a5ff0aSAndreas Hindborg where 13650a5ff0aSAndreas Hindborg [u8]: Index<Idx, Output = [u8]>, 13750a5ff0aSAndreas Hindborg { 13850a5ff0aSAndreas Hindborg type Output = Self; 13950a5ff0aSAndreas Hindborg index(&self, index: Idx) -> &Self::Output14050a5ff0aSAndreas Hindborg fn index(&self, index: Idx) -> &Self::Output { 14150a5ff0aSAndreas Hindborg BStr::from_bytes(&self.0[index]) 14250a5ff0aSAndreas Hindborg } 14350a5ff0aSAndreas Hindborg } 14450a5ff0aSAndreas Hindborg 145d2e3f798SAndreas Hindborg impl AsRef<BStr> for [u8] { as_ref(&self) -> &BStr146d2e3f798SAndreas Hindborg fn as_ref(&self) -> &BStr { 147d2e3f798SAndreas Hindborg BStr::from_bytes(self) 148d2e3f798SAndreas Hindborg } 149d2e3f798SAndreas Hindborg } 150d2e3f798SAndreas Hindborg 151d2e3f798SAndreas Hindborg impl AsRef<BStr> for BStr { as_ref(&self) -> &BStr152d2e3f798SAndreas Hindborg fn as_ref(&self) -> &BStr { 153d2e3f798SAndreas Hindborg self 154d2e3f798SAndreas Hindborg } 155d2e3f798SAndreas Hindborg } 156d2e3f798SAndreas Hindborg 157650ec515SGary Guo /// Creates a new [`BStr`] from a string literal. 158650ec515SGary Guo /// 159650ec515SGary Guo /// `b_str!` converts the supplied string literal to byte string, so non-ASCII 160650ec515SGary Guo /// characters can be included. 161650ec515SGary Guo /// 162650ec515SGary Guo /// # Examples 163650ec515SGary Guo /// 164650ec515SGary Guo /// ``` 165650ec515SGary Guo /// # use kernel::b_str; 166650ec515SGary Guo /// # use kernel::str::BStr; 167650ec515SGary Guo /// const MY_BSTR: &BStr = b_str!("My awesome BStr!"); 168650ec515SGary Guo /// ``` 169650ec515SGary Guo #[macro_export] 170650ec515SGary Guo macro_rules! b_str { 171650ec515SGary Guo ($str:literal) => {{ 172650ec515SGary Guo const S: &'static str = $str; 1734951ddd5SYutaro Ohno const C: &'static $crate::str::BStr = $crate::str::BStr::from_bytes(S.as_bytes()); 174650ec515SGary Guo C 175650ec515SGary Guo }}; 176650ec515SGary Guo } 177650ec515SGary Guo 178d126d238SGary Guo /// Possible errors when using conversion functions in [`CStr`]. 179d126d238SGary Guo #[derive(Debug, Clone, Copy)] 180d126d238SGary Guo pub enum CStrConvertError { 181d126d238SGary Guo /// Supplied bytes contain an interior `NUL`. 182d126d238SGary Guo InteriorNul, 183d126d238SGary Guo 184d126d238SGary Guo /// Supplied bytes are not terminated by `NUL`. 185d126d238SGary Guo NotNulTerminated, 186d126d238SGary Guo } 187d126d238SGary Guo 188d126d238SGary Guo impl From<CStrConvertError> for Error { 189d126d238SGary Guo #[inline] from(_: CStrConvertError) -> Error190d126d238SGary Guo fn from(_: CStrConvertError) -> Error { 191d126d238SGary Guo EINVAL 192d126d238SGary Guo } 193d126d238SGary Guo } 194d126d238SGary Guo 195d126d238SGary Guo /// A string that is guaranteed to have exactly one `NUL` byte, which is at the 196d126d238SGary Guo /// end. 197d126d238SGary Guo /// 198d126d238SGary Guo /// Used for interoperability with kernel APIs that take C strings. 199d126d238SGary Guo #[repr(transparent)] 200d126d238SGary Guo pub struct CStr([u8]); 201d126d238SGary Guo 202d126d238SGary Guo impl CStr { 203d126d238SGary Guo /// Returns the length of this string excluding `NUL`. 204d126d238SGary Guo #[inline] len(&self) -> usize205d126d238SGary Guo pub const fn len(&self) -> usize { 206d126d238SGary Guo self.len_with_nul() - 1 207d126d238SGary Guo } 208d126d238SGary Guo 209d126d238SGary Guo /// Returns the length of this string with `NUL`. 210d126d238SGary Guo #[inline] len_with_nul(&self) -> usize211d126d238SGary Guo pub const fn len_with_nul(&self) -> usize { 212db4f72c9SMiguel Ojeda if self.0.is_empty() { 213d126d238SGary Guo // SAFETY: This is one of the invariant of `CStr`. 214d126d238SGary Guo // We add a `unreachable_unchecked` here to hint the optimizer that 215d126d238SGary Guo // the value returned from this function is non-zero. 216d126d238SGary Guo unsafe { core::hint::unreachable_unchecked() }; 217d126d238SGary Guo } 218d126d238SGary Guo self.0.len() 219d126d238SGary Guo } 220d126d238SGary Guo 221d126d238SGary Guo /// Returns `true` if the string only includes `NUL`. 222d126d238SGary Guo #[inline] is_empty(&self) -> bool223d126d238SGary Guo pub const fn is_empty(&self) -> bool { 224d126d238SGary Guo self.len() == 0 225d126d238SGary Guo } 226d126d238SGary Guo 227d126d238SGary Guo /// Wraps a raw C string pointer. 228d126d238SGary Guo /// 229d126d238SGary Guo /// # Safety 230d126d238SGary Guo /// 231d126d238SGary Guo /// `ptr` must be a valid pointer to a `NUL`-terminated C string, and it must 232d126d238SGary Guo /// last at least `'a`. When `CStr` is alive, the memory pointed by `ptr` 233d126d238SGary Guo /// must not be mutated. 234d126d238SGary Guo #[inline] from_char_ptr<'a>(ptr: *const crate::ffi::c_char) -> &'a Self235d072acdaSGary Guo pub unsafe fn from_char_ptr<'a>(ptr: *const crate::ffi::c_char) -> &'a Self { 236d126d238SGary Guo // SAFETY: The safety precondition guarantees `ptr` is a valid pointer 237d126d238SGary Guo // to a `NUL`-terminated C string. 238d126d238SGary Guo let len = unsafe { bindings::strlen(ptr) } + 1; 239d126d238SGary Guo // SAFETY: Lifetime guaranteed by the safety precondition. 2409b98be76SGary Guo let bytes = unsafe { core::slice::from_raw_parts(ptr as _, len) }; 241d126d238SGary Guo // SAFETY: As `len` is returned by `strlen`, `bytes` does not contain interior `NUL`. 242d126d238SGary Guo // As we have added 1 to `len`, the last byte is known to be `NUL`. 243d126d238SGary Guo unsafe { Self::from_bytes_with_nul_unchecked(bytes) } 244d126d238SGary Guo } 245d126d238SGary Guo 246d126d238SGary Guo /// Creates a [`CStr`] from a `[u8]`. 247d126d238SGary Guo /// 248d126d238SGary Guo /// The provided slice must be `NUL`-terminated, does not contain any 249d126d238SGary Guo /// interior `NUL` bytes. from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, CStrConvertError>250d126d238SGary Guo pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, CStrConvertError> { 251d126d238SGary Guo if bytes.is_empty() { 252d126d238SGary Guo return Err(CStrConvertError::NotNulTerminated); 253d126d238SGary Guo } 254d126d238SGary Guo if bytes[bytes.len() - 1] != 0 { 255d126d238SGary Guo return Err(CStrConvertError::NotNulTerminated); 256d126d238SGary Guo } 257d126d238SGary Guo let mut i = 0; 258d126d238SGary Guo // `i + 1 < bytes.len()` allows LLVM to optimize away bounds checking, 259d126d238SGary Guo // while it couldn't optimize away bounds checks for `i < bytes.len() - 1`. 260d126d238SGary Guo while i + 1 < bytes.len() { 261d126d238SGary Guo if bytes[i] == 0 { 262d126d238SGary Guo return Err(CStrConvertError::InteriorNul); 263d126d238SGary Guo } 264d126d238SGary Guo i += 1; 265d126d238SGary Guo } 266d126d238SGary Guo // SAFETY: We just checked that all properties hold. 267d126d238SGary Guo Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) }) 268d126d238SGary Guo } 269d126d238SGary Guo 270d126d238SGary Guo /// Creates a [`CStr`] from a `[u8]` without performing any additional 271d126d238SGary Guo /// checks. 272d126d238SGary Guo /// 273d126d238SGary Guo /// # Safety 274d126d238SGary Guo /// 275d126d238SGary Guo /// `bytes` *must* end with a `NUL` byte, and should only have a single 276d126d238SGary Guo /// `NUL` byte (or the string will be truncated). 277d126d238SGary Guo #[inline] from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr278d126d238SGary Guo pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr { 279d126d238SGary Guo // SAFETY: Properties of `bytes` guaranteed by the safety precondition. 280d126d238SGary Guo unsafe { core::mem::transmute(bytes) } 281d126d238SGary Guo } 282d126d238SGary Guo 283a321f3adSDanilo Krummrich /// Creates a mutable [`CStr`] from a `[u8]` without performing any 284a321f3adSDanilo Krummrich /// additional checks. 285a321f3adSDanilo Krummrich /// 286a321f3adSDanilo Krummrich /// # Safety 287a321f3adSDanilo Krummrich /// 288a321f3adSDanilo Krummrich /// `bytes` *must* end with a `NUL` byte, and should only have a single 289a321f3adSDanilo Krummrich /// `NUL` byte (or the string will be truncated). 290a321f3adSDanilo Krummrich #[inline] from_bytes_with_nul_unchecked_mut(bytes: &mut [u8]) -> &mut CStr291a321f3adSDanilo Krummrich pub unsafe fn from_bytes_with_nul_unchecked_mut(bytes: &mut [u8]) -> &mut CStr { 292a321f3adSDanilo Krummrich // SAFETY: Properties of `bytes` guaranteed by the safety precondition. 293a321f3adSDanilo Krummrich unsafe { &mut *(bytes as *mut [u8] as *mut CStr) } 294a321f3adSDanilo Krummrich } 295a321f3adSDanilo Krummrich 296d126d238SGary Guo /// Returns a C pointer to the string. 297d126d238SGary Guo #[inline] as_char_ptr(&self) -> *const crate::ffi::c_char298d072acdaSGary Guo pub const fn as_char_ptr(&self) -> *const crate::ffi::c_char { 2999b98be76SGary Guo self.0.as_ptr() 300d126d238SGary Guo } 301d126d238SGary Guo 3028cfce47dSValentin Obst /// Convert the string to a byte slice without the trailing `NUL` byte. 303d126d238SGary Guo #[inline] as_bytes(&self) -> &[u8]304d126d238SGary Guo pub fn as_bytes(&self) -> &[u8] { 305d126d238SGary Guo &self.0[..self.len()] 306d126d238SGary Guo } 307d126d238SGary Guo 3088cfce47dSValentin Obst /// Convert the string to a byte slice containing the trailing `NUL` byte. 309d126d238SGary Guo #[inline] as_bytes_with_nul(&self) -> &[u8]310d126d238SGary Guo pub const fn as_bytes_with_nul(&self) -> &[u8] { 311d126d238SGary Guo &self.0 312d126d238SGary Guo } 313d126d238SGary Guo 314d126d238SGary Guo /// Yields a [`&str`] slice if the [`CStr`] contains valid UTF-8. 315d126d238SGary Guo /// 316d126d238SGary Guo /// If the contents of the [`CStr`] are valid UTF-8 data, this 317d126d238SGary Guo /// function will return the corresponding [`&str`] slice. Otherwise, 318d126d238SGary Guo /// it will return an error with details of where UTF-8 validation failed. 319d126d238SGary Guo /// 320d126d238SGary Guo /// # Examples 321d126d238SGary Guo /// 322d126d238SGary Guo /// ``` 323d126d238SGary Guo /// # use kernel::str::CStr; 324b6357e26SDaniel Sedlak /// let cstr = CStr::from_bytes_with_nul(b"foo\0")?; 325d126d238SGary Guo /// assert_eq!(cstr.to_str(), Ok("foo")); 326b6357e26SDaniel Sedlak /// # Ok::<(), kernel::error::Error>(()) 327d126d238SGary Guo /// ``` 328d126d238SGary Guo #[inline] to_str(&self) -> Result<&str, core::str::Utf8Error>329d126d238SGary Guo pub fn to_str(&self) -> Result<&str, core::str::Utf8Error> { 330d126d238SGary Guo core::str::from_utf8(self.as_bytes()) 331d126d238SGary Guo } 332d126d238SGary Guo 333d126d238SGary Guo /// Unsafely convert this [`CStr`] into a [`&str`], without checking for 334d126d238SGary Guo /// valid UTF-8. 335d126d238SGary Guo /// 336d126d238SGary Guo /// # Safety 337d126d238SGary Guo /// 338d126d238SGary Guo /// The contents must be valid UTF-8. 339d126d238SGary Guo /// 340d126d238SGary Guo /// # Examples 341d126d238SGary Guo /// 342d126d238SGary Guo /// ``` 343d126d238SGary Guo /// # use kernel::c_str; 344d126d238SGary Guo /// # use kernel::str::CStr; 3454c62348dSValentin Obst /// let bar = c_str!("ツ"); 346d126d238SGary Guo /// // SAFETY: String literals are guaranteed to be valid UTF-8 347d126d238SGary Guo /// // by the Rust compiler. 348d126d238SGary Guo /// assert_eq!(unsafe { bar.as_str_unchecked() }, "ツ"); 349d126d238SGary Guo /// ``` 350d126d238SGary Guo #[inline] as_str_unchecked(&self) -> &str351d126d238SGary Guo pub unsafe fn as_str_unchecked(&self) -> &str { 352db4f72c9SMiguel Ojeda // SAFETY: TODO. 353d126d238SGary Guo unsafe { core::str::from_utf8_unchecked(self.as_bytes()) } 354d126d238SGary Guo } 35566bd7533SAlice Ryhl 35666bd7533SAlice Ryhl /// Convert this [`CStr`] into a [`CString`] by allocating memory and 35766bd7533SAlice Ryhl /// copying over the string data. to_cstring(&self) -> Result<CString, AllocError>35866bd7533SAlice Ryhl pub fn to_cstring(&self) -> Result<CString, AllocError> { 35966bd7533SAlice Ryhl CString::try_from(self) 36066bd7533SAlice Ryhl } 361a321f3adSDanilo Krummrich 362a321f3adSDanilo Krummrich /// Converts this [`CStr`] to its ASCII lower case equivalent in-place. 363a321f3adSDanilo Krummrich /// 364a321f3adSDanilo Krummrich /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', 365a321f3adSDanilo Krummrich /// but non-ASCII letters are unchanged. 366a321f3adSDanilo Krummrich /// 367a321f3adSDanilo Krummrich /// To return a new lowercased value without modifying the existing one, use 368a321f3adSDanilo Krummrich /// [`to_ascii_lowercase()`]. 369a321f3adSDanilo Krummrich /// 370a321f3adSDanilo Krummrich /// [`to_ascii_lowercase()`]: #method.to_ascii_lowercase make_ascii_lowercase(&mut self)371a321f3adSDanilo Krummrich pub fn make_ascii_lowercase(&mut self) { 372a321f3adSDanilo Krummrich // INVARIANT: This doesn't introduce or remove NUL bytes in the C 373a321f3adSDanilo Krummrich // string. 374a321f3adSDanilo Krummrich self.0.make_ascii_lowercase(); 375a321f3adSDanilo Krummrich } 376a321f3adSDanilo Krummrich 377a321f3adSDanilo Krummrich /// Converts this [`CStr`] to its ASCII upper case equivalent in-place. 378a321f3adSDanilo Krummrich /// 379a321f3adSDanilo Krummrich /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', 380a321f3adSDanilo Krummrich /// but non-ASCII letters are unchanged. 381a321f3adSDanilo Krummrich /// 382a321f3adSDanilo Krummrich /// To return a new uppercased value without modifying the existing one, use 383a321f3adSDanilo Krummrich /// [`to_ascii_uppercase()`]. 384a321f3adSDanilo Krummrich /// 385a321f3adSDanilo Krummrich /// [`to_ascii_uppercase()`]: #method.to_ascii_uppercase make_ascii_uppercase(&mut self)386a321f3adSDanilo Krummrich pub fn make_ascii_uppercase(&mut self) { 387a321f3adSDanilo Krummrich // INVARIANT: This doesn't introduce or remove NUL bytes in the C 388a321f3adSDanilo Krummrich // string. 389a321f3adSDanilo Krummrich self.0.make_ascii_uppercase(); 390a321f3adSDanilo Krummrich } 391a321f3adSDanilo Krummrich 392a321f3adSDanilo Krummrich /// Returns a copy of this [`CString`] where each character is mapped to its 393a321f3adSDanilo Krummrich /// ASCII lower case equivalent. 394a321f3adSDanilo Krummrich /// 395a321f3adSDanilo Krummrich /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', 396a321f3adSDanilo Krummrich /// but non-ASCII letters are unchanged. 397a321f3adSDanilo Krummrich /// 398a321f3adSDanilo Krummrich /// To lowercase the value in-place, use [`make_ascii_lowercase`]. 399a321f3adSDanilo Krummrich /// 400a321f3adSDanilo Krummrich /// [`make_ascii_lowercase`]: str::make_ascii_lowercase to_ascii_lowercase(&self) -> Result<CString, AllocError>401a321f3adSDanilo Krummrich pub fn to_ascii_lowercase(&self) -> Result<CString, AllocError> { 402a321f3adSDanilo Krummrich let mut s = self.to_cstring()?; 403a321f3adSDanilo Krummrich 404a321f3adSDanilo Krummrich s.make_ascii_lowercase(); 405a321f3adSDanilo Krummrich 406a321f3adSDanilo Krummrich Ok(s) 407a321f3adSDanilo Krummrich } 408a321f3adSDanilo Krummrich 409a321f3adSDanilo Krummrich /// Returns a copy of this [`CString`] where each character is mapped to its 410a321f3adSDanilo Krummrich /// ASCII upper case equivalent. 411a321f3adSDanilo Krummrich /// 412a321f3adSDanilo Krummrich /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', 413a321f3adSDanilo Krummrich /// but non-ASCII letters are unchanged. 414a321f3adSDanilo Krummrich /// 415a321f3adSDanilo Krummrich /// To uppercase the value in-place, use [`make_ascii_uppercase`]. 416a321f3adSDanilo Krummrich /// 417a321f3adSDanilo Krummrich /// [`make_ascii_uppercase`]: str::make_ascii_uppercase to_ascii_uppercase(&self) -> Result<CString, AllocError>418a321f3adSDanilo Krummrich pub fn to_ascii_uppercase(&self) -> Result<CString, AllocError> { 419a321f3adSDanilo Krummrich let mut s = self.to_cstring()?; 420a321f3adSDanilo Krummrich 421a321f3adSDanilo Krummrich s.make_ascii_uppercase(); 422a321f3adSDanilo Krummrich 423a321f3adSDanilo Krummrich Ok(s) 424a321f3adSDanilo Krummrich } 425d126d238SGary Guo } 426d126d238SGary Guo 427c07e67bdSGary Guo impl fmt::Display for CStr { 428c07e67bdSGary Guo /// Formats printable ASCII characters, escaping the rest. 429c07e67bdSGary Guo /// 430c07e67bdSGary Guo /// ``` 431c07e67bdSGary Guo /// # use kernel::c_str; 432cf36a495SMiguel Ojeda /// # use kernel::fmt; 433c07e67bdSGary Guo /// # use kernel::str::CStr; 434c07e67bdSGary Guo /// # use kernel::str::CString; 435c07e67bdSGary Guo /// let penguin = c_str!(""); 436b6357e26SDaniel Sedlak /// let s = CString::try_from_fmt(fmt!("{}", penguin))?; 437c07e67bdSGary Guo /// assert_eq!(s.as_bytes_with_nul(), "\\xf0\\x9f\\x90\\xa7\0".as_bytes()); 438c07e67bdSGary Guo /// 439c07e67bdSGary Guo /// let ascii = c_str!("so \"cool\""); 440b6357e26SDaniel Sedlak /// let s = CString::try_from_fmt(fmt!("{}", ascii))?; 441c07e67bdSGary Guo /// assert_eq!(s.as_bytes_with_nul(), "so \"cool\"\0".as_bytes()); 442b6357e26SDaniel Sedlak /// # Ok::<(), kernel::error::Error>(()) 443c07e67bdSGary Guo /// ``` fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result444c07e67bdSGary Guo fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 445c07e67bdSGary Guo for &c in self.as_bytes() { 446c07e67bdSGary Guo if (0x20..0x7f).contains(&c) { 447c07e67bdSGary Guo // Printable character. 448c07e67bdSGary Guo f.write_char(c as char)?; 449c07e67bdSGary Guo } else { 450*211dcf77SMiguel Ojeda write!(f, "\\x{c:02x}")?; 451c07e67bdSGary Guo } 452c07e67bdSGary Guo } 453c07e67bdSGary Guo Ok(()) 454c07e67bdSGary Guo } 455c07e67bdSGary Guo } 456c07e67bdSGary Guo 457c07e67bdSGary Guo impl fmt::Debug for CStr { 458c07e67bdSGary Guo /// Formats printable ASCII characters with a double quote on either end, escaping the rest. 459c07e67bdSGary Guo /// 460c07e67bdSGary Guo /// ``` 461c07e67bdSGary Guo /// # use kernel::c_str; 462cf36a495SMiguel Ojeda /// # use kernel::fmt; 463c07e67bdSGary Guo /// # use kernel::str::CStr; 464c07e67bdSGary Guo /// # use kernel::str::CString; 465c07e67bdSGary Guo /// let penguin = c_str!(""); 466b6357e26SDaniel Sedlak /// let s = CString::try_from_fmt(fmt!("{:?}", penguin))?; 467c07e67bdSGary Guo /// assert_eq!(s.as_bytes_with_nul(), "\"\\xf0\\x9f\\x90\\xa7\"\0".as_bytes()); 468c07e67bdSGary Guo /// 469c07e67bdSGary Guo /// // Embedded double quotes are escaped. 470c07e67bdSGary Guo /// let ascii = c_str!("so \"cool\""); 471b6357e26SDaniel Sedlak /// let s = CString::try_from_fmt(fmt!("{:?}", ascii))?; 472c07e67bdSGary Guo /// assert_eq!(s.as_bytes_with_nul(), "\"so \\\"cool\\\"\"\0".as_bytes()); 473b6357e26SDaniel Sedlak /// # Ok::<(), kernel::error::Error>(()) 474c07e67bdSGary Guo /// ``` fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result475c07e67bdSGary Guo fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 476c07e67bdSGary Guo f.write_str("\"")?; 477c07e67bdSGary Guo for &c in self.as_bytes() { 478c07e67bdSGary Guo match c { 479c07e67bdSGary Guo // Printable characters. 480c07e67bdSGary Guo b'\"' => f.write_str("\\\"")?, 481c07e67bdSGary Guo 0x20..=0x7e => f.write_char(c as char)?, 482*211dcf77SMiguel Ojeda _ => write!(f, "\\x{c:02x}")?, 483c07e67bdSGary Guo } 484c07e67bdSGary Guo } 485c07e67bdSGary Guo f.write_str("\"") 486c07e67bdSGary Guo } 487c07e67bdSGary Guo } 488c07e67bdSGary Guo 489c07e67bdSGary Guo impl AsRef<BStr> for CStr { 490c07e67bdSGary Guo #[inline] as_ref(&self) -> &BStr491c07e67bdSGary Guo fn as_ref(&self) -> &BStr { 4924951ddd5SYutaro Ohno BStr::from_bytes(self.as_bytes()) 493c07e67bdSGary Guo } 494c07e67bdSGary Guo } 495c07e67bdSGary Guo 496c07e67bdSGary Guo impl Deref for CStr { 497c07e67bdSGary Guo type Target = BStr; 498c07e67bdSGary Guo 499c07e67bdSGary Guo #[inline] deref(&self) -> &Self::Target500c07e67bdSGary Guo fn deref(&self) -> &Self::Target { 5014951ddd5SYutaro Ohno self.as_ref() 502c07e67bdSGary Guo } 503c07e67bdSGary Guo } 504c07e67bdSGary Guo 505c07e67bdSGary Guo impl Index<ops::RangeFrom<usize>> for CStr { 506c07e67bdSGary Guo type Output = CStr; 507c07e67bdSGary Guo 508c07e67bdSGary Guo #[inline] index(&self, index: ops::RangeFrom<usize>) -> &Self::Output509c07e67bdSGary Guo fn index(&self, index: ops::RangeFrom<usize>) -> &Self::Output { 510c07e67bdSGary Guo // Delegate bounds checking to slice. 511c07e67bdSGary Guo // Assign to _ to mute clippy's unnecessary operation warning. 512c07e67bdSGary Guo let _ = &self.as_bytes()[index.start..]; 513c07e67bdSGary Guo // SAFETY: We just checked the bounds. 514c07e67bdSGary Guo unsafe { Self::from_bytes_with_nul_unchecked(&self.0[index.start..]) } 515c07e67bdSGary Guo } 516c07e67bdSGary Guo } 517c07e67bdSGary Guo 518c07e67bdSGary Guo impl Index<ops::RangeFull> for CStr { 519c07e67bdSGary Guo type Output = CStr; 520c07e67bdSGary Guo 521c07e67bdSGary Guo #[inline] index(&self, _index: ops::RangeFull) -> &Self::Output522c07e67bdSGary Guo fn index(&self, _index: ops::RangeFull) -> &Self::Output { 523c07e67bdSGary Guo self 524c07e67bdSGary Guo } 525c07e67bdSGary Guo } 526c07e67bdSGary Guo 527c07e67bdSGary Guo mod private { 528c07e67bdSGary Guo use core::ops; 529c07e67bdSGary Guo 530c07e67bdSGary Guo // Marker trait for index types that can be forward to `BStr`. 531c07e67bdSGary Guo pub trait CStrIndex {} 532c07e67bdSGary Guo 533c07e67bdSGary Guo impl CStrIndex for usize {} 534c07e67bdSGary Guo impl CStrIndex for ops::Range<usize> {} 535c07e67bdSGary Guo impl CStrIndex for ops::RangeInclusive<usize> {} 536c07e67bdSGary Guo impl CStrIndex for ops::RangeToInclusive<usize> {} 537c07e67bdSGary Guo } 538c07e67bdSGary Guo 539c07e67bdSGary Guo impl<Idx> Index<Idx> for CStr 540c07e67bdSGary Guo where 541c07e67bdSGary Guo Idx: private::CStrIndex, 542c07e67bdSGary Guo BStr: Index<Idx>, 543c07e67bdSGary Guo { 544c07e67bdSGary Guo type Output = <BStr as Index<Idx>>::Output; 545c07e67bdSGary Guo 546c07e67bdSGary Guo #[inline] index(&self, index: Idx) -> &Self::Output547c07e67bdSGary Guo fn index(&self, index: Idx) -> &Self::Output { 5484951ddd5SYutaro Ohno &self.as_ref()[index] 549c07e67bdSGary Guo } 550c07e67bdSGary Guo } 551c07e67bdSGary Guo 552b18cb00eSGary Guo /// Creates a new [`CStr`] from a string literal. 553b18cb00eSGary Guo /// 554b18cb00eSGary Guo /// The string literal should not contain any `NUL` bytes. 555b18cb00eSGary Guo /// 556b18cb00eSGary Guo /// # Examples 557b18cb00eSGary Guo /// 558b18cb00eSGary Guo /// ``` 559b18cb00eSGary Guo /// # use kernel::c_str; 560b18cb00eSGary Guo /// # use kernel::str::CStr; 561b18cb00eSGary Guo /// const MY_CSTR: &CStr = c_str!("My awesome CStr!"); 562b18cb00eSGary Guo /// ``` 563b18cb00eSGary Guo #[macro_export] 564b18cb00eSGary Guo macro_rules! c_str { 565b18cb00eSGary Guo ($str:expr) => {{ 566b18cb00eSGary Guo const S: &str = concat!($str, "\0"); 567b18cb00eSGary Guo const C: &$crate::str::CStr = match $crate::str::CStr::from_bytes_with_nul(S.as_bytes()) { 568b18cb00eSGary Guo Ok(v) => v, 569b18cb00eSGary Guo Err(_) => panic!("string contains interior NUL"), 570b18cb00eSGary Guo }; 571b18cb00eSGary Guo C 572b18cb00eSGary Guo }}; 573b18cb00eSGary Guo } 574b18cb00eSGary Guo 575985f1f09SMilan Landaverde #[cfg(test)] 5762a87f8b0SMiguel Ojeda #[expect(clippy::items_after_test_module)] 577985f1f09SMilan Landaverde mod tests { 578985f1f09SMilan Landaverde use super::*; 579eb6f92cdSDanilo Krummrich 580eb6f92cdSDanilo Krummrich struct String(CString); 581eb6f92cdSDanilo Krummrich 582eb6f92cdSDanilo Krummrich impl String { from_fmt(args: fmt::Arguments<'_>) -> Self583eb6f92cdSDanilo Krummrich fn from_fmt(args: fmt::Arguments<'_>) -> Self { 584eb6f92cdSDanilo Krummrich String(CString::try_from_fmt(args).unwrap()) 585eb6f92cdSDanilo Krummrich } 586eb6f92cdSDanilo Krummrich } 587eb6f92cdSDanilo Krummrich 588eb6f92cdSDanilo Krummrich impl Deref for String { 589eb6f92cdSDanilo Krummrich type Target = str; 590eb6f92cdSDanilo Krummrich deref(&self) -> &str591eb6f92cdSDanilo Krummrich fn deref(&self) -> &str { 592eb6f92cdSDanilo Krummrich self.0.to_str().unwrap() 593eb6f92cdSDanilo Krummrich } 594eb6f92cdSDanilo Krummrich } 595eb6f92cdSDanilo Krummrich 596eb6f92cdSDanilo Krummrich macro_rules! format { 597eb6f92cdSDanilo Krummrich ($($f:tt)*) => ({ 598eb6f92cdSDanilo Krummrich &*String::from_fmt(kernel::fmt!($($f)*)) 599eb6f92cdSDanilo Krummrich }) 600eb6f92cdSDanilo Krummrich } 6014951ddd5SYutaro Ohno 6022a87f8b0SMiguel Ojeda const ALL_ASCII_CHARS: &str = 6034951ddd5SYutaro Ohno "\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\x09\\x0a\\x0b\\x0c\\x0d\\x0e\\x0f\ 6044951ddd5SYutaro Ohno \\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f \ 6054951ddd5SYutaro Ohno !\"#$%&'()*+,-./0123456789:;<=>?@\ 6064951ddd5SYutaro Ohno ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\\x7f\ 6074951ddd5SYutaro Ohno \\x80\\x81\\x82\\x83\\x84\\x85\\x86\\x87\\x88\\x89\\x8a\\x8b\\x8c\\x8d\\x8e\\x8f\ 6084951ddd5SYutaro Ohno \\x90\\x91\\x92\\x93\\x94\\x95\\x96\\x97\\x98\\x99\\x9a\\x9b\\x9c\\x9d\\x9e\\x9f\ 6094951ddd5SYutaro Ohno \\xa0\\xa1\\xa2\\xa3\\xa4\\xa5\\xa6\\xa7\\xa8\\xa9\\xaa\\xab\\xac\\xad\\xae\\xaf\ 6104951ddd5SYutaro Ohno \\xb0\\xb1\\xb2\\xb3\\xb4\\xb5\\xb6\\xb7\\xb8\\xb9\\xba\\xbb\\xbc\\xbd\\xbe\\xbf\ 6114951ddd5SYutaro Ohno \\xc0\\xc1\\xc2\\xc3\\xc4\\xc5\\xc6\\xc7\\xc8\\xc9\\xca\\xcb\\xcc\\xcd\\xce\\xcf\ 6124951ddd5SYutaro Ohno \\xd0\\xd1\\xd2\\xd3\\xd4\\xd5\\xd6\\xd7\\xd8\\xd9\\xda\\xdb\\xdc\\xdd\\xde\\xdf\ 6134951ddd5SYutaro Ohno \\xe0\\xe1\\xe2\\xe3\\xe4\\xe5\\xe6\\xe7\\xe8\\xe9\\xea\\xeb\\xec\\xed\\xee\\xef\ 6144951ddd5SYutaro Ohno \\xf0\\xf1\\xf2\\xf3\\xf4\\xf5\\xf6\\xf7\\xf8\\xf9\\xfa\\xfb\\xfc\\xfd\\xfe\\xff"; 615985f1f09SMilan Landaverde 616985f1f09SMilan Landaverde #[test] test_cstr_to_str()617985f1f09SMilan Landaverde fn test_cstr_to_str() { 618985f1f09SMilan Landaverde let good_bytes = b"\xf0\x9f\xa6\x80\0"; 619985f1f09SMilan Landaverde let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap(); 620985f1f09SMilan Landaverde let checked_str = checked_cstr.to_str().unwrap(); 621985f1f09SMilan Landaverde assert_eq!(checked_str, ""); 622985f1f09SMilan Landaverde } 623985f1f09SMilan Landaverde 624985f1f09SMilan Landaverde #[test] 625985f1f09SMilan Landaverde #[should_panic] test_cstr_to_str_panic()626985f1f09SMilan Landaverde fn test_cstr_to_str_panic() { 627985f1f09SMilan Landaverde let bad_bytes = b"\xc3\x28\0"; 628985f1f09SMilan Landaverde let checked_cstr = CStr::from_bytes_with_nul(bad_bytes).unwrap(); 629985f1f09SMilan Landaverde checked_cstr.to_str().unwrap(); 630985f1f09SMilan Landaverde } 631985f1f09SMilan Landaverde 632985f1f09SMilan Landaverde #[test] test_cstr_as_str_unchecked()633985f1f09SMilan Landaverde fn test_cstr_as_str_unchecked() { 634985f1f09SMilan Landaverde let good_bytes = b"\xf0\x9f\x90\xA7\0"; 635985f1f09SMilan Landaverde let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap(); 6362a87f8b0SMiguel Ojeda // SAFETY: The contents come from a string literal which contains valid UTF-8. 637985f1f09SMilan Landaverde let unchecked_str = unsafe { checked_cstr.as_str_unchecked() }; 638985f1f09SMilan Landaverde assert_eq!(unchecked_str, ""); 639985f1f09SMilan Landaverde } 6404951ddd5SYutaro Ohno 6414951ddd5SYutaro Ohno #[test] test_cstr_display()6424951ddd5SYutaro Ohno fn test_cstr_display() { 6434951ddd5SYutaro Ohno let hello_world = CStr::from_bytes_with_nul(b"hello, world!\0").unwrap(); 644*211dcf77SMiguel Ojeda assert_eq!(format!("{hello_world}"), "hello, world!"); 6454951ddd5SYutaro Ohno let non_printables = CStr::from_bytes_with_nul(b"\x01\x09\x0a\0").unwrap(); 646*211dcf77SMiguel Ojeda assert_eq!(format!("{non_printables}"), "\\x01\\x09\\x0a"); 6474951ddd5SYutaro Ohno let non_ascii = CStr::from_bytes_with_nul(b"d\xe9j\xe0 vu\0").unwrap(); 648*211dcf77SMiguel Ojeda assert_eq!(format!("{non_ascii}"), "d\\xe9j\\xe0 vu"); 6494951ddd5SYutaro Ohno let good_bytes = CStr::from_bytes_with_nul(b"\xf0\x9f\xa6\x80\0").unwrap(); 650*211dcf77SMiguel Ojeda assert_eq!(format!("{good_bytes}"), "\\xf0\\x9f\\xa6\\x80"); 6514951ddd5SYutaro Ohno } 6524951ddd5SYutaro Ohno 6534951ddd5SYutaro Ohno #[test] test_cstr_display_all_bytes()6544951ddd5SYutaro Ohno fn test_cstr_display_all_bytes() { 6554951ddd5SYutaro Ohno let mut bytes: [u8; 256] = [0; 256]; 6564951ddd5SYutaro Ohno // fill `bytes` with [1..=255] + [0] 6574951ddd5SYutaro Ohno for i in u8::MIN..=u8::MAX { 6584951ddd5SYutaro Ohno bytes[i as usize] = i.wrapping_add(1); 6594951ddd5SYutaro Ohno } 6604951ddd5SYutaro Ohno let cstr = CStr::from_bytes_with_nul(&bytes).unwrap(); 661*211dcf77SMiguel Ojeda assert_eq!(format!("{cstr}"), ALL_ASCII_CHARS); 6624951ddd5SYutaro Ohno } 6634951ddd5SYutaro Ohno 6644951ddd5SYutaro Ohno #[test] test_cstr_debug()6654951ddd5SYutaro Ohno fn test_cstr_debug() { 6664951ddd5SYutaro Ohno let hello_world = CStr::from_bytes_with_nul(b"hello, world!\0").unwrap(); 667*211dcf77SMiguel Ojeda assert_eq!(format!("{hello_world:?}"), "\"hello, world!\""); 6684951ddd5SYutaro Ohno let non_printables = CStr::from_bytes_with_nul(b"\x01\x09\x0a\0").unwrap(); 669*211dcf77SMiguel Ojeda assert_eq!(format!("{non_printables:?}"), "\"\\x01\\x09\\x0a\""); 6704951ddd5SYutaro Ohno let non_ascii = CStr::from_bytes_with_nul(b"d\xe9j\xe0 vu\0").unwrap(); 671*211dcf77SMiguel Ojeda assert_eq!(format!("{non_ascii:?}"), "\"d\\xe9j\\xe0 vu\""); 6724951ddd5SYutaro Ohno let good_bytes = CStr::from_bytes_with_nul(b"\xf0\x9f\xa6\x80\0").unwrap(); 673*211dcf77SMiguel Ojeda assert_eq!(format!("{good_bytes:?}"), "\"\\xf0\\x9f\\xa6\\x80\""); 6744951ddd5SYutaro Ohno } 6754951ddd5SYutaro Ohno 6764951ddd5SYutaro Ohno #[test] test_bstr_display()6774951ddd5SYutaro Ohno fn test_bstr_display() { 6784951ddd5SYutaro Ohno let hello_world = BStr::from_bytes(b"hello, world!"); 679*211dcf77SMiguel Ojeda assert_eq!(format!("{hello_world}"), "hello, world!"); 6804951ddd5SYutaro Ohno let escapes = BStr::from_bytes(b"_\t_\n_\r_\\_\'_\"_"); 681*211dcf77SMiguel Ojeda assert_eq!(format!("{escapes}"), "_\\t_\\n_\\r_\\_'_\"_"); 6824951ddd5SYutaro Ohno let others = BStr::from_bytes(b"\x01"); 683*211dcf77SMiguel Ojeda assert_eq!(format!("{others}"), "\\x01"); 6844951ddd5SYutaro Ohno let non_ascii = BStr::from_bytes(b"d\xe9j\xe0 vu"); 685*211dcf77SMiguel Ojeda assert_eq!(format!("{non_ascii}"), "d\\xe9j\\xe0 vu"); 6864951ddd5SYutaro Ohno let good_bytes = BStr::from_bytes(b"\xf0\x9f\xa6\x80"); 687*211dcf77SMiguel Ojeda assert_eq!(format!("{good_bytes}"), "\\xf0\\x9f\\xa6\\x80"); 6884951ddd5SYutaro Ohno } 6894951ddd5SYutaro Ohno 6904951ddd5SYutaro Ohno #[test] test_bstr_debug()6914951ddd5SYutaro Ohno fn test_bstr_debug() { 6924951ddd5SYutaro Ohno let hello_world = BStr::from_bytes(b"hello, world!"); 693*211dcf77SMiguel Ojeda assert_eq!(format!("{hello_world:?}"), "\"hello, world!\""); 6944951ddd5SYutaro Ohno let escapes = BStr::from_bytes(b"_\t_\n_\r_\\_\'_\"_"); 695*211dcf77SMiguel Ojeda assert_eq!(format!("{escapes:?}"), "\"_\\t_\\n_\\r_\\\\_'_\\\"_\""); 6964951ddd5SYutaro Ohno let others = BStr::from_bytes(b"\x01"); 697*211dcf77SMiguel Ojeda assert_eq!(format!("{others:?}"), "\"\\x01\""); 6984951ddd5SYutaro Ohno let non_ascii = BStr::from_bytes(b"d\xe9j\xe0 vu"); 699*211dcf77SMiguel Ojeda assert_eq!(format!("{non_ascii:?}"), "\"d\\xe9j\\xe0 vu\""); 7004951ddd5SYutaro Ohno let good_bytes = BStr::from_bytes(b"\xf0\x9f\xa6\x80"); 701*211dcf77SMiguel Ojeda assert_eq!(format!("{good_bytes:?}"), "\"\\xf0\\x9f\\xa6\\x80\""); 7024951ddd5SYutaro Ohno } 703985f1f09SMilan Landaverde } 704985f1f09SMilan Landaverde 705247b365dSWedson Almeida Filho /// Allows formatting of [`fmt::Arguments`] into a raw buffer. 706247b365dSWedson Almeida Filho /// 707247b365dSWedson Almeida Filho /// It does not fail if callers write past the end of the buffer so that they can calculate the 708247b365dSWedson Almeida Filho /// size required to fit everything. 709247b365dSWedson Almeida Filho /// 710247b365dSWedson Almeida Filho /// # Invariants 711247b365dSWedson Almeida Filho /// 712247b365dSWedson Almeida Filho /// The memory region between `pos` (inclusive) and `end` (exclusive) is valid for writes if `pos` 713247b365dSWedson Almeida Filho /// is less than `end`. 714247b365dSWedson Almeida Filho pub(crate) struct RawFormatter { 715247b365dSWedson Almeida Filho // Use `usize` to use `saturating_*` functions. 716247b365dSWedson Almeida Filho beg: usize, 717247b365dSWedson Almeida Filho pos: usize, 718247b365dSWedson Almeida Filho end: usize, 719247b365dSWedson Almeida Filho } 720247b365dSWedson Almeida Filho 721247b365dSWedson Almeida Filho impl RawFormatter { 72265e1e497SWedson Almeida Filho /// Creates a new instance of [`RawFormatter`] with an empty buffer. new() -> Self72365e1e497SWedson Almeida Filho fn new() -> Self { 72465e1e497SWedson Almeida Filho // INVARIANT: The buffer is empty, so the region that needs to be writable is empty. 72565e1e497SWedson Almeida Filho Self { 72665e1e497SWedson Almeida Filho beg: 0, 72765e1e497SWedson Almeida Filho pos: 0, 72865e1e497SWedson Almeida Filho end: 0, 72965e1e497SWedson Almeida Filho } 73065e1e497SWedson Almeida Filho } 73165e1e497SWedson Almeida Filho 732247b365dSWedson Almeida Filho /// Creates a new instance of [`RawFormatter`] with the given buffer pointers. 733247b365dSWedson Almeida Filho /// 734247b365dSWedson Almeida Filho /// # Safety 735247b365dSWedson Almeida Filho /// 736247b365dSWedson Almeida Filho /// If `pos` is less than `end`, then the region between `pos` (inclusive) and `end` 737247b365dSWedson Almeida Filho /// (exclusive) must be valid for writes for the lifetime of the returned [`RawFormatter`]. from_ptrs(pos: *mut u8, end: *mut u8) -> Self738247b365dSWedson Almeida Filho pub(crate) unsafe fn from_ptrs(pos: *mut u8, end: *mut u8) -> Self { 73988e8c2ecSPatrick Blass // INVARIANT: The safety requirements guarantee the type invariants. 740247b365dSWedson Almeida Filho Self { 741247b365dSWedson Almeida Filho beg: pos as _, 742247b365dSWedson Almeida Filho pos: pos as _, 743247b365dSWedson Almeida Filho end: end as _, 744247b365dSWedson Almeida Filho } 745247b365dSWedson Almeida Filho } 746247b365dSWedson Almeida Filho 747fffed679SWedson Almeida Filho /// Creates a new instance of [`RawFormatter`] with the given buffer. 748fffed679SWedson Almeida Filho /// 749fffed679SWedson Almeida Filho /// # Safety 750fffed679SWedson Almeida Filho /// 751fffed679SWedson Almeida Filho /// The memory region starting at `buf` and extending for `len` bytes must be valid for writes 752fffed679SWedson Almeida Filho /// for the lifetime of the returned [`RawFormatter`]. from_buffer(buf: *mut u8, len: usize) -> Self753fffed679SWedson Almeida Filho pub(crate) unsafe fn from_buffer(buf: *mut u8, len: usize) -> Self { 754fffed679SWedson Almeida Filho let pos = buf as usize; 755fffed679SWedson Almeida Filho // INVARIANT: We ensure that `end` is never less then `buf`, and the safety requirements 756fffed679SWedson Almeida Filho // guarantees that the memory region is valid for writes. 757fffed679SWedson Almeida Filho Self { 758fffed679SWedson Almeida Filho pos, 759fffed679SWedson Almeida Filho beg: pos, 760fffed679SWedson Almeida Filho end: pos.saturating_add(len), 761fffed679SWedson Almeida Filho } 762fffed679SWedson Almeida Filho } 763fffed679SWedson Almeida Filho 764247b365dSWedson Almeida Filho /// Returns the current insert position. 765247b365dSWedson Almeida Filho /// 766247b365dSWedson Almeida Filho /// N.B. It may point to invalid memory. pos(&self) -> *mut u8767247b365dSWedson Almeida Filho pub(crate) fn pos(&self) -> *mut u8 { 768247b365dSWedson Almeida Filho self.pos as _ 769247b365dSWedson Almeida Filho } 77065e1e497SWedson Almeida Filho 771b6cda913SValentin Obst /// Returns the number of bytes written to the formatter. bytes_written(&self) -> usize77265e1e497SWedson Almeida Filho pub(crate) fn bytes_written(&self) -> usize { 77365e1e497SWedson Almeida Filho self.pos - self.beg 77465e1e497SWedson Almeida Filho } 775247b365dSWedson Almeida Filho } 776247b365dSWedson Almeida Filho 777247b365dSWedson Almeida Filho impl fmt::Write for RawFormatter { write_str(&mut self, s: &str) -> fmt::Result778247b365dSWedson Almeida Filho fn write_str(&mut self, s: &str) -> fmt::Result { 779247b365dSWedson Almeida Filho // `pos` value after writing `len` bytes. This does not have to be bounded by `end`, but we 780247b365dSWedson Almeida Filho // don't want it to wrap around to 0. 781247b365dSWedson Almeida Filho let pos_new = self.pos.saturating_add(s.len()); 782247b365dSWedson Almeida Filho 783247b365dSWedson Almeida Filho // Amount that we can copy. `saturating_sub` ensures we get 0 if `pos` goes past `end`. 784247b365dSWedson Almeida Filho let len_to_copy = core::cmp::min(pos_new, self.end).saturating_sub(self.pos); 785247b365dSWedson Almeida Filho 786247b365dSWedson Almeida Filho if len_to_copy > 0 { 787247b365dSWedson Almeida Filho // SAFETY: If `len_to_copy` is non-zero, then we know `pos` has not gone past `end` 788247b365dSWedson Almeida Filho // yet, so it is valid for write per the type invariants. 789247b365dSWedson Almeida Filho unsafe { 790247b365dSWedson Almeida Filho core::ptr::copy_nonoverlapping( 791247b365dSWedson Almeida Filho s.as_bytes().as_ptr(), 792247b365dSWedson Almeida Filho self.pos as *mut u8, 793247b365dSWedson Almeida Filho len_to_copy, 794247b365dSWedson Almeida Filho ) 795247b365dSWedson Almeida Filho }; 796247b365dSWedson Almeida Filho } 797247b365dSWedson Almeida Filho 798247b365dSWedson Almeida Filho self.pos = pos_new; 799247b365dSWedson Almeida Filho Ok(()) 800247b365dSWedson Almeida Filho } 801247b365dSWedson Almeida Filho } 802fffed679SWedson Almeida Filho 803fffed679SWedson Almeida Filho /// Allows formatting of [`fmt::Arguments`] into a raw buffer. 804fffed679SWedson Almeida Filho /// 805fffed679SWedson Almeida Filho /// Fails if callers attempt to write more than will fit in the buffer. 806fffed679SWedson Almeida Filho pub(crate) struct Formatter(RawFormatter); 807fffed679SWedson Almeida Filho 808fffed679SWedson Almeida Filho impl Formatter { 809fffed679SWedson Almeida Filho /// Creates a new instance of [`Formatter`] with the given buffer. 810fffed679SWedson Almeida Filho /// 811fffed679SWedson Almeida Filho /// # Safety 812fffed679SWedson Almeida Filho /// 813fffed679SWedson Almeida Filho /// The memory region starting at `buf` and extending for `len` bytes must be valid for writes 814fffed679SWedson Almeida Filho /// for the lifetime of the returned [`Formatter`]. from_buffer(buf: *mut u8, len: usize) -> Self815fffed679SWedson Almeida Filho pub(crate) unsafe fn from_buffer(buf: *mut u8, len: usize) -> Self { 816fffed679SWedson Almeida Filho // SAFETY: The safety requirements of this function satisfy those of the callee. 817fffed679SWedson Almeida Filho Self(unsafe { RawFormatter::from_buffer(buf, len) }) 818fffed679SWedson Almeida Filho } 819fffed679SWedson Almeida Filho } 820fffed679SWedson Almeida Filho 821fffed679SWedson Almeida Filho impl Deref for Formatter { 822fffed679SWedson Almeida Filho type Target = RawFormatter; 823fffed679SWedson Almeida Filho deref(&self) -> &Self::Target824fffed679SWedson Almeida Filho fn deref(&self) -> &Self::Target { 825fffed679SWedson Almeida Filho &self.0 826fffed679SWedson Almeida Filho } 827fffed679SWedson Almeida Filho } 828fffed679SWedson Almeida Filho 829fffed679SWedson Almeida Filho impl fmt::Write for Formatter { write_str(&mut self, s: &str) -> fmt::Result830fffed679SWedson Almeida Filho fn write_str(&mut self, s: &str) -> fmt::Result { 831fffed679SWedson Almeida Filho self.0.write_str(s)?; 832fffed679SWedson Almeida Filho 833fffed679SWedson Almeida Filho // Fail the request if we go past the end of the buffer. 834fffed679SWedson Almeida Filho if self.0.pos > self.0.end { 835fffed679SWedson Almeida Filho Err(fmt::Error) 836fffed679SWedson Almeida Filho } else { 837fffed679SWedson Almeida Filho Ok(()) 838fffed679SWedson Almeida Filho } 839fffed679SWedson Almeida Filho } 840fffed679SWedson Almeida Filho } 84165e1e497SWedson Almeida Filho 84265e1e497SWedson Almeida Filho /// An owned string that is guaranteed to have exactly one `NUL` byte, which is at the end. 84365e1e497SWedson Almeida Filho /// 84465e1e497SWedson Almeida Filho /// Used for interoperability with kernel APIs that take C strings. 84565e1e497SWedson Almeida Filho /// 84665e1e497SWedson Almeida Filho /// # Invariants 84765e1e497SWedson Almeida Filho /// 84865e1e497SWedson Almeida Filho /// The string is always `NUL`-terminated and contains no other `NUL` bytes. 84965e1e497SWedson Almeida Filho /// 85065e1e497SWedson Almeida Filho /// # Examples 85165e1e497SWedson Almeida Filho /// 85265e1e497SWedson Almeida Filho /// ``` 853cf36a495SMiguel Ojeda /// use kernel::{str::CString, fmt}; 85465e1e497SWedson Almeida Filho /// 855b6357e26SDaniel Sedlak /// let s = CString::try_from_fmt(fmt!("{}{}{}", "abc", 10, 20))?; 85665e1e497SWedson Almeida Filho /// assert_eq!(s.as_bytes_with_nul(), "abc1020\0".as_bytes()); 85765e1e497SWedson Almeida Filho /// 85865e1e497SWedson Almeida Filho /// let tmp = "testing"; 859b6357e26SDaniel Sedlak /// let s = CString::try_from_fmt(fmt!("{tmp}{}", 123))?; 86065e1e497SWedson Almeida Filho /// assert_eq!(s.as_bytes_with_nul(), "testing123\0".as_bytes()); 86165e1e497SWedson Almeida Filho /// 86265e1e497SWedson Almeida Filho /// // This fails because it has an embedded `NUL` byte. 86365e1e497SWedson Almeida Filho /// let s = CString::try_from_fmt(fmt!("a\0b{}", 123)); 86465e1e497SWedson Almeida Filho /// assert_eq!(s.is_ok(), false); 865b6357e26SDaniel Sedlak /// # Ok::<(), kernel::error::Error>(()) 86665e1e497SWedson Almeida Filho /// ``` 86765e1e497SWedson Almeida Filho pub struct CString { 86858eff8e8SDanilo Krummrich buf: KVec<u8>, 86965e1e497SWedson Almeida Filho } 87065e1e497SWedson Almeida Filho 87165e1e497SWedson Almeida Filho impl CString { 87265e1e497SWedson Almeida Filho /// Creates an instance of [`CString`] from the given formatted arguments. try_from_fmt(args: fmt::Arguments<'_>) -> Result<Self, Error>87365e1e497SWedson Almeida Filho pub fn try_from_fmt(args: fmt::Arguments<'_>) -> Result<Self, Error> { 87465e1e497SWedson Almeida Filho // Calculate the size needed (formatted string plus `NUL` terminator). 87565e1e497SWedson Almeida Filho let mut f = RawFormatter::new(); 87665e1e497SWedson Almeida Filho f.write_fmt(args)?; 87765e1e497SWedson Almeida Filho f.write_str("\0")?; 87865e1e497SWedson Almeida Filho let size = f.bytes_written(); 87965e1e497SWedson Almeida Filho 88065e1e497SWedson Almeida Filho // Allocate a vector with the required number of bytes, and write to it. 88158eff8e8SDanilo Krummrich let mut buf = KVec::with_capacity(size, GFP_KERNEL)?; 88265e1e497SWedson Almeida Filho // SAFETY: The buffer stored in `buf` is at least of size `size` and is valid for writes. 88365e1e497SWedson Almeida Filho let mut f = unsafe { Formatter::from_buffer(buf.as_mut_ptr(), size) }; 88465e1e497SWedson Almeida Filho f.write_fmt(args)?; 88565e1e497SWedson Almeida Filho f.write_str("\0")?; 88665e1e497SWedson Almeida Filho 88765e1e497SWedson Almeida Filho // SAFETY: The number of bytes that can be written to `f` is bounded by `size`, which is 88865e1e497SWedson Almeida Filho // `buf`'s capacity. The contents of the buffer have been initialised by writes to `f`. 88965e1e497SWedson Almeida Filho unsafe { buf.set_len(f.bytes_written()) }; 89065e1e497SWedson Almeida Filho 89165e1e497SWedson Almeida Filho // Check that there are no `NUL` bytes before the end. 89265e1e497SWedson Almeida Filho // SAFETY: The buffer is valid for read because `f.bytes_written()` is bounded by `size` 89365e1e497SWedson Almeida Filho // (which the minimum buffer size) and is non-zero (we wrote at least the `NUL` terminator) 89465e1e497SWedson Almeida Filho // so `f.bytes_written() - 1` doesn't underflow. 8959b98be76SGary Guo let ptr = unsafe { bindings::memchr(buf.as_ptr().cast(), 0, f.bytes_written() - 1) }; 89665e1e497SWedson Almeida Filho if !ptr.is_null() { 89765e1e497SWedson Almeida Filho return Err(EINVAL); 89865e1e497SWedson Almeida Filho } 89965e1e497SWedson Almeida Filho 90065e1e497SWedson Almeida Filho // INVARIANT: We wrote the `NUL` terminator and checked above that no other `NUL` bytes 90165e1e497SWedson Almeida Filho // exist in the buffer. 90265e1e497SWedson Almeida Filho Ok(Self { buf }) 90365e1e497SWedson Almeida Filho } 90465e1e497SWedson Almeida Filho } 90565e1e497SWedson Almeida Filho 90665e1e497SWedson Almeida Filho impl Deref for CString { 90765e1e497SWedson Almeida Filho type Target = CStr; 90865e1e497SWedson Almeida Filho deref(&self) -> &Self::Target90965e1e497SWedson Almeida Filho fn deref(&self) -> &Self::Target { 91065e1e497SWedson Almeida Filho // SAFETY: The type invariants guarantee that the string is `NUL`-terminated and that no 91165e1e497SWedson Almeida Filho // other `NUL` bytes exist. 91265e1e497SWedson Almeida Filho unsafe { CStr::from_bytes_with_nul_unchecked(self.buf.as_slice()) } 91365e1e497SWedson Almeida Filho } 91465e1e497SWedson Almeida Filho } 915ef320549SWedson Almeida Filho 916a321f3adSDanilo Krummrich impl DerefMut for CString { deref_mut(&mut self) -> &mut Self::Target917a321f3adSDanilo Krummrich fn deref_mut(&mut self) -> &mut Self::Target { 918a321f3adSDanilo Krummrich // SAFETY: A `CString` is always NUL-terminated and contains no other 919a321f3adSDanilo Krummrich // NUL bytes. 920a321f3adSDanilo Krummrich unsafe { CStr::from_bytes_with_nul_unchecked_mut(self.buf.as_mut_slice()) } 921a321f3adSDanilo Krummrich } 922a321f3adSDanilo Krummrich } 923a321f3adSDanilo Krummrich 92466bd7533SAlice Ryhl impl<'a> TryFrom<&'a CStr> for CString { 92566bd7533SAlice Ryhl type Error = AllocError; 92666bd7533SAlice Ryhl try_from(cstr: &'a CStr) -> Result<CString, AllocError>92766bd7533SAlice Ryhl fn try_from(cstr: &'a CStr) -> Result<CString, AllocError> { 92858eff8e8SDanilo Krummrich let mut buf = KVec::new(); 92966bd7533SAlice Ryhl 93058eff8e8SDanilo Krummrich buf.extend_from_slice(cstr.as_bytes_with_nul(), GFP_KERNEL)?; 93166bd7533SAlice Ryhl 93266bd7533SAlice Ryhl // INVARIANT: The `CStr` and `CString` types have the same invariants for 93366bd7533SAlice Ryhl // the string data, and we copied it over without changes. 93466bd7533SAlice Ryhl Ok(CString { buf }) 93566bd7533SAlice Ryhl } 93666bd7533SAlice Ryhl } 93766bd7533SAlice Ryhl 938c3f41b00SAsahi Lina impl fmt::Debug for CString { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result939c3f41b00SAsahi Lina fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 940c3f41b00SAsahi Lina fmt::Debug::fmt(&**self, f) 941c3f41b00SAsahi Lina } 942c3f41b00SAsahi Lina } 943c3f41b00SAsahi Lina 944ef320549SWedson Almeida Filho /// A convenience alias for [`core::format_args`]. 945ef320549SWedson Almeida Filho #[macro_export] 946ef320549SWedson Almeida Filho macro_rules! fmt { 947ef320549SWedson Almeida Filho ($($f:tt)*) => ( core::format_args!($($f)*) ) 948ef320549SWedson Almeida Filho } 949