1247b365dSWedson Almeida Filho // SPDX-License-Identifier: GPL-2.0 2247b365dSWedson Almeida Filho 3247b365dSWedson Almeida Filho //! String representations. 4247b365dSWedson Almeida Filho 566bd7533SAlice Ryhl use alloc::alloc::AllocError; 665e1e497SWedson Almeida Filho use alloc::vec::Vec; 7c07e67bdSGary Guo use core::fmt::{self, Write}; 8c07e67bdSGary Guo use core::ops::{self, Deref, Index}; 9247b365dSWedson Almeida Filho 10d126d238SGary Guo use crate::{ 11d126d238SGary Guo bindings, 12d126d238SGary Guo error::{code::*, Error}, 13d126d238SGary Guo }; 14d126d238SGary Guo 157c597746SGary Guo /// Byte string without UTF-8 validity guarantee. 167c597746SGary Guo /// 177c597746SGary Guo /// `BStr` is simply an alias to `[u8]`, but has a more evident semantical meaning. 187c597746SGary Guo pub type BStr = [u8]; 197c597746SGary Guo 20650ec515SGary Guo /// Creates a new [`BStr`] from a string literal. 21650ec515SGary Guo /// 22650ec515SGary Guo /// `b_str!` converts the supplied string literal to byte string, so non-ASCII 23650ec515SGary Guo /// characters can be included. 24650ec515SGary Guo /// 25650ec515SGary Guo /// # Examples 26650ec515SGary Guo /// 27650ec515SGary Guo /// ``` 28650ec515SGary Guo /// # use kernel::b_str; 29650ec515SGary Guo /// # use kernel::str::BStr; 30650ec515SGary Guo /// const MY_BSTR: &BStr = b_str!("My awesome BStr!"); 31650ec515SGary Guo /// ``` 32650ec515SGary Guo #[macro_export] 33650ec515SGary Guo macro_rules! b_str { 34650ec515SGary Guo ($str:literal) => {{ 35650ec515SGary Guo const S: &'static str = $str; 36650ec515SGary Guo const C: &'static $crate::str::BStr = S.as_bytes(); 37650ec515SGary Guo C 38650ec515SGary Guo }}; 39650ec515SGary Guo } 40650ec515SGary Guo 41d126d238SGary Guo /// Possible errors when using conversion functions in [`CStr`]. 42d126d238SGary Guo #[derive(Debug, Clone, Copy)] 43d126d238SGary Guo pub enum CStrConvertError { 44d126d238SGary Guo /// Supplied bytes contain an interior `NUL`. 45d126d238SGary Guo InteriorNul, 46d126d238SGary Guo 47d126d238SGary Guo /// Supplied bytes are not terminated by `NUL`. 48d126d238SGary Guo NotNulTerminated, 49d126d238SGary Guo } 50d126d238SGary Guo 51d126d238SGary Guo impl From<CStrConvertError> for Error { 52d126d238SGary Guo #[inline] from(_: CStrConvertError) -> Error53d126d238SGary Guo fn from(_: CStrConvertError) -> Error { 54d126d238SGary Guo EINVAL 55d126d238SGary Guo } 56d126d238SGary Guo } 57d126d238SGary Guo 58d126d238SGary Guo /// A string that is guaranteed to have exactly one `NUL` byte, which is at the 59d126d238SGary Guo /// end. 60d126d238SGary Guo /// 61d126d238SGary Guo /// Used for interoperability with kernel APIs that take C strings. 62d126d238SGary Guo #[repr(transparent)] 63d126d238SGary Guo pub struct CStr([u8]); 64d126d238SGary Guo 65d126d238SGary Guo impl CStr { 66d126d238SGary Guo /// Returns the length of this string excluding `NUL`. 67d126d238SGary Guo #[inline] len(&self) -> usize68d126d238SGary Guo pub const fn len(&self) -> usize { 69d126d238SGary Guo self.len_with_nul() - 1 70d126d238SGary Guo } 71d126d238SGary Guo 72d126d238SGary Guo /// Returns the length of this string with `NUL`. 73d126d238SGary Guo #[inline] len_with_nul(&self) -> usize74d126d238SGary Guo pub const fn len_with_nul(&self) -> usize { 75d126d238SGary Guo // SAFETY: This is one of the invariant of `CStr`. 76d126d238SGary Guo // We add a `unreachable_unchecked` here to hint the optimizer that 77d126d238SGary Guo // the value returned from this function is non-zero. 78d126d238SGary Guo if self.0.is_empty() { 79d126d238SGary Guo unsafe { core::hint::unreachable_unchecked() }; 80d126d238SGary Guo } 81d126d238SGary Guo self.0.len() 82d126d238SGary Guo } 83d126d238SGary Guo 84d126d238SGary Guo /// Returns `true` if the string only includes `NUL`. 85d126d238SGary Guo #[inline] is_empty(&self) -> bool86d126d238SGary Guo pub const fn is_empty(&self) -> bool { 87d126d238SGary Guo self.len() == 0 88d126d238SGary Guo } 89d126d238SGary Guo 90d126d238SGary Guo /// Wraps a raw C string pointer. 91d126d238SGary Guo /// 92d126d238SGary Guo /// # Safety 93d126d238SGary Guo /// 94d126d238SGary Guo /// `ptr` must be a valid pointer to a `NUL`-terminated C string, and it must 95d126d238SGary Guo /// last at least `'a`. When `CStr` is alive, the memory pointed by `ptr` 96d126d238SGary Guo /// must not be mutated. 97d126d238SGary Guo #[inline] from_char_ptr<'a>(ptr: *const core::ffi::c_char) -> &'a Self98d126d238SGary Guo pub unsafe fn from_char_ptr<'a>(ptr: *const core::ffi::c_char) -> &'a Self { 99d126d238SGary Guo // SAFETY: The safety precondition guarantees `ptr` is a valid pointer 100d126d238SGary Guo // to a `NUL`-terminated C string. 101d126d238SGary Guo let len = unsafe { bindings::strlen(ptr) } + 1; 102d126d238SGary Guo // SAFETY: Lifetime guaranteed by the safety precondition. 103d126d238SGary Guo let bytes = unsafe { core::slice::from_raw_parts(ptr as _, len as _) }; 104d126d238SGary Guo // SAFETY: As `len` is returned by `strlen`, `bytes` does not contain interior `NUL`. 105d126d238SGary Guo // As we have added 1 to `len`, the last byte is known to be `NUL`. 106d126d238SGary Guo unsafe { Self::from_bytes_with_nul_unchecked(bytes) } 107d126d238SGary Guo } 108d126d238SGary Guo 109d126d238SGary Guo /// Creates a [`CStr`] from a `[u8]`. 110d126d238SGary Guo /// 111d126d238SGary Guo /// The provided slice must be `NUL`-terminated, does not contain any 112d126d238SGary Guo /// interior `NUL` bytes. from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, CStrConvertError>113d126d238SGary Guo pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, CStrConvertError> { 114d126d238SGary Guo if bytes.is_empty() { 115d126d238SGary Guo return Err(CStrConvertError::NotNulTerminated); 116d126d238SGary Guo } 117d126d238SGary Guo if bytes[bytes.len() - 1] != 0 { 118d126d238SGary Guo return Err(CStrConvertError::NotNulTerminated); 119d126d238SGary Guo } 120d126d238SGary Guo let mut i = 0; 121d126d238SGary Guo // `i + 1 < bytes.len()` allows LLVM to optimize away bounds checking, 122d126d238SGary Guo // while it couldn't optimize away bounds checks for `i < bytes.len() - 1`. 123d126d238SGary Guo while i + 1 < bytes.len() { 124d126d238SGary Guo if bytes[i] == 0 { 125d126d238SGary Guo return Err(CStrConvertError::InteriorNul); 126d126d238SGary Guo } 127d126d238SGary Guo i += 1; 128d126d238SGary Guo } 129d126d238SGary Guo // SAFETY: We just checked that all properties hold. 130d126d238SGary Guo Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) }) 131d126d238SGary Guo } 132d126d238SGary Guo 133d126d238SGary Guo /// Creates a [`CStr`] from a `[u8]` without performing any additional 134d126d238SGary Guo /// checks. 135d126d238SGary Guo /// 136d126d238SGary Guo /// # Safety 137d126d238SGary Guo /// 138d126d238SGary Guo /// `bytes` *must* end with a `NUL` byte, and should only have a single 139d126d238SGary Guo /// `NUL` byte (or the string will be truncated). 140d126d238SGary Guo #[inline] from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr141d126d238SGary Guo pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr { 142d126d238SGary Guo // SAFETY: Properties of `bytes` guaranteed by the safety precondition. 143d126d238SGary Guo unsafe { core::mem::transmute(bytes) } 144d126d238SGary Guo } 145d126d238SGary Guo 146d126d238SGary Guo /// Returns a C pointer to the string. 147d126d238SGary Guo #[inline] as_char_ptr(&self) -> *const core::ffi::c_char148d126d238SGary Guo pub const fn as_char_ptr(&self) -> *const core::ffi::c_char { 149d126d238SGary Guo self.0.as_ptr() as _ 150d126d238SGary Guo } 151d126d238SGary Guo 152d126d238SGary Guo /// Convert the string to a byte slice without the trailing 0 byte. 153d126d238SGary Guo #[inline] as_bytes(&self) -> &[u8]154d126d238SGary Guo pub fn as_bytes(&self) -> &[u8] { 155d126d238SGary Guo &self.0[..self.len()] 156d126d238SGary Guo } 157d126d238SGary Guo 158d126d238SGary Guo /// Convert the string to a byte slice containing the trailing 0 byte. 159d126d238SGary Guo #[inline] as_bytes_with_nul(&self) -> &[u8]160d126d238SGary Guo pub const fn as_bytes_with_nul(&self) -> &[u8] { 161d126d238SGary Guo &self.0 162d126d238SGary Guo } 163d126d238SGary Guo 164d126d238SGary Guo /// Yields a [`&str`] slice if the [`CStr`] contains valid UTF-8. 165d126d238SGary Guo /// 166d126d238SGary Guo /// If the contents of the [`CStr`] are valid UTF-8 data, this 167d126d238SGary Guo /// function will return the corresponding [`&str`] slice. Otherwise, 168d126d238SGary Guo /// it will return an error with details of where UTF-8 validation failed. 169d126d238SGary Guo /// 170d126d238SGary Guo /// # Examples 171d126d238SGary Guo /// 172d126d238SGary Guo /// ``` 173d126d238SGary Guo /// # use kernel::str::CStr; 174d126d238SGary Guo /// let cstr = CStr::from_bytes_with_nul(b"foo\0").unwrap(); 175d126d238SGary Guo /// assert_eq!(cstr.to_str(), Ok("foo")); 176d126d238SGary Guo /// ``` 177d126d238SGary Guo #[inline] to_str(&self) -> Result<&str, core::str::Utf8Error>178d126d238SGary Guo pub fn to_str(&self) -> Result<&str, core::str::Utf8Error> { 179d126d238SGary Guo core::str::from_utf8(self.as_bytes()) 180d126d238SGary Guo } 181d126d238SGary Guo 182d126d238SGary Guo /// Unsafely convert this [`CStr`] into a [`&str`], without checking for 183d126d238SGary Guo /// valid UTF-8. 184d126d238SGary Guo /// 185d126d238SGary Guo /// # Safety 186d126d238SGary Guo /// 187d126d238SGary Guo /// The contents must be valid UTF-8. 188d126d238SGary Guo /// 189d126d238SGary Guo /// # Examples 190d126d238SGary Guo /// 191d126d238SGary Guo /// ``` 192d126d238SGary Guo /// # use kernel::c_str; 193d126d238SGary Guo /// # use kernel::str::CStr; 194d126d238SGary Guo /// // SAFETY: String literals are guaranteed to be valid UTF-8 195d126d238SGary Guo /// // by the Rust compiler. 196d126d238SGary Guo /// let bar = c_str!("ツ"); 197d126d238SGary Guo /// assert_eq!(unsafe { bar.as_str_unchecked() }, "ツ"); 198d126d238SGary Guo /// ``` 199d126d238SGary Guo #[inline] as_str_unchecked(&self) -> &str200d126d238SGary Guo pub unsafe fn as_str_unchecked(&self) -> &str { 201d126d238SGary Guo unsafe { core::str::from_utf8_unchecked(self.as_bytes()) } 202d126d238SGary Guo } 20366bd7533SAlice Ryhl 20466bd7533SAlice Ryhl /// Convert this [`CStr`] into a [`CString`] by allocating memory and 20566bd7533SAlice Ryhl /// copying over the string data. to_cstring(&self) -> Result<CString, AllocError>20666bd7533SAlice Ryhl pub fn to_cstring(&self) -> Result<CString, AllocError> { 20766bd7533SAlice Ryhl CString::try_from(self) 20866bd7533SAlice Ryhl } 209d126d238SGary Guo } 210d126d238SGary Guo 211c07e67bdSGary Guo impl fmt::Display for CStr { 212c07e67bdSGary Guo /// Formats printable ASCII characters, escaping the rest. 213c07e67bdSGary Guo /// 214c07e67bdSGary Guo /// ``` 215c07e67bdSGary Guo /// # use kernel::c_str; 216*cf36a495SMiguel Ojeda /// # use kernel::fmt; 217c07e67bdSGary Guo /// # use kernel::str::CStr; 218c07e67bdSGary Guo /// # use kernel::str::CString; 219c07e67bdSGary Guo /// let penguin = c_str!(""); 220c07e67bdSGary Guo /// let s = CString::try_from_fmt(fmt!("{}", penguin)).unwrap(); 221c07e67bdSGary Guo /// assert_eq!(s.as_bytes_with_nul(), "\\xf0\\x9f\\x90\\xa7\0".as_bytes()); 222c07e67bdSGary Guo /// 223c07e67bdSGary Guo /// let ascii = c_str!("so \"cool\""); 224c07e67bdSGary Guo /// let s = CString::try_from_fmt(fmt!("{}", ascii)).unwrap(); 225c07e67bdSGary Guo /// assert_eq!(s.as_bytes_with_nul(), "so \"cool\"\0".as_bytes()); 226c07e67bdSGary Guo /// ``` fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result227c07e67bdSGary Guo fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 228c07e67bdSGary Guo for &c in self.as_bytes() { 229c07e67bdSGary Guo if (0x20..0x7f).contains(&c) { 230c07e67bdSGary Guo // Printable character. 231c07e67bdSGary Guo f.write_char(c as char)?; 232c07e67bdSGary Guo } else { 233c07e67bdSGary Guo write!(f, "\\x{:02x}", c)?; 234c07e67bdSGary Guo } 235c07e67bdSGary Guo } 236c07e67bdSGary Guo Ok(()) 237c07e67bdSGary Guo } 238c07e67bdSGary Guo } 239c07e67bdSGary Guo 240c07e67bdSGary Guo impl fmt::Debug for CStr { 241c07e67bdSGary Guo /// Formats printable ASCII characters with a double quote on either end, escaping the rest. 242c07e67bdSGary Guo /// 243c07e67bdSGary Guo /// ``` 244c07e67bdSGary Guo /// # use kernel::c_str; 245*cf36a495SMiguel Ojeda /// # use kernel::fmt; 246c07e67bdSGary Guo /// # use kernel::str::CStr; 247c07e67bdSGary Guo /// # use kernel::str::CString; 248c07e67bdSGary Guo /// let penguin = c_str!(""); 249c07e67bdSGary Guo /// let s = CString::try_from_fmt(fmt!("{:?}", penguin)).unwrap(); 250c07e67bdSGary Guo /// assert_eq!(s.as_bytes_with_nul(), "\"\\xf0\\x9f\\x90\\xa7\"\0".as_bytes()); 251c07e67bdSGary Guo /// 252c07e67bdSGary Guo /// // Embedded double quotes are escaped. 253c07e67bdSGary Guo /// let ascii = c_str!("so \"cool\""); 254c07e67bdSGary Guo /// let s = CString::try_from_fmt(fmt!("{:?}", ascii)).unwrap(); 255c07e67bdSGary Guo /// assert_eq!(s.as_bytes_with_nul(), "\"so \\\"cool\\\"\"\0".as_bytes()); 256c07e67bdSGary Guo /// ``` fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result257c07e67bdSGary Guo fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 258c07e67bdSGary Guo f.write_str("\"")?; 259c07e67bdSGary Guo for &c in self.as_bytes() { 260c07e67bdSGary Guo match c { 261c07e67bdSGary Guo // Printable characters. 262c07e67bdSGary Guo b'\"' => f.write_str("\\\"")?, 263c07e67bdSGary Guo 0x20..=0x7e => f.write_char(c as char)?, 264c07e67bdSGary Guo _ => write!(f, "\\x{:02x}", c)?, 265c07e67bdSGary Guo } 266c07e67bdSGary Guo } 267c07e67bdSGary Guo f.write_str("\"") 268c07e67bdSGary Guo } 269c07e67bdSGary Guo } 270c07e67bdSGary Guo 271c07e67bdSGary Guo impl AsRef<BStr> for CStr { 272c07e67bdSGary Guo #[inline] as_ref(&self) -> &BStr273c07e67bdSGary Guo fn as_ref(&self) -> &BStr { 274c07e67bdSGary Guo self.as_bytes() 275c07e67bdSGary Guo } 276c07e67bdSGary Guo } 277c07e67bdSGary Guo 278c07e67bdSGary Guo impl Deref for CStr { 279c07e67bdSGary Guo type Target = BStr; 280c07e67bdSGary Guo 281c07e67bdSGary Guo #[inline] deref(&self) -> &Self::Target282c07e67bdSGary Guo fn deref(&self) -> &Self::Target { 283c07e67bdSGary Guo self.as_bytes() 284c07e67bdSGary Guo } 285c07e67bdSGary Guo } 286c07e67bdSGary Guo 287c07e67bdSGary Guo impl Index<ops::RangeFrom<usize>> for CStr { 288c07e67bdSGary Guo type Output = CStr; 289c07e67bdSGary Guo 290c07e67bdSGary Guo #[inline] index(&self, index: ops::RangeFrom<usize>) -> &Self::Output291c07e67bdSGary Guo fn index(&self, index: ops::RangeFrom<usize>) -> &Self::Output { 292c07e67bdSGary Guo // Delegate bounds checking to slice. 293c07e67bdSGary Guo // Assign to _ to mute clippy's unnecessary operation warning. 294c07e67bdSGary Guo let _ = &self.as_bytes()[index.start..]; 295c07e67bdSGary Guo // SAFETY: We just checked the bounds. 296c07e67bdSGary Guo unsafe { Self::from_bytes_with_nul_unchecked(&self.0[index.start..]) } 297c07e67bdSGary Guo } 298c07e67bdSGary Guo } 299c07e67bdSGary Guo 300c07e67bdSGary Guo impl Index<ops::RangeFull> for CStr { 301c07e67bdSGary Guo type Output = CStr; 302c07e67bdSGary Guo 303c07e67bdSGary Guo #[inline] index(&self, _index: ops::RangeFull) -> &Self::Output304c07e67bdSGary Guo fn index(&self, _index: ops::RangeFull) -> &Self::Output { 305c07e67bdSGary Guo self 306c07e67bdSGary Guo } 307c07e67bdSGary Guo } 308c07e67bdSGary Guo 309c07e67bdSGary Guo mod private { 310c07e67bdSGary Guo use core::ops; 311c07e67bdSGary Guo 312c07e67bdSGary Guo // Marker trait for index types that can be forward to `BStr`. 313c07e67bdSGary Guo pub trait CStrIndex {} 314c07e67bdSGary Guo 315c07e67bdSGary Guo impl CStrIndex for usize {} 316c07e67bdSGary Guo impl CStrIndex for ops::Range<usize> {} 317c07e67bdSGary Guo impl CStrIndex for ops::RangeInclusive<usize> {} 318c07e67bdSGary Guo impl CStrIndex for ops::RangeToInclusive<usize> {} 319c07e67bdSGary Guo } 320c07e67bdSGary Guo 321c07e67bdSGary Guo impl<Idx> Index<Idx> for CStr 322c07e67bdSGary Guo where 323c07e67bdSGary Guo Idx: private::CStrIndex, 324c07e67bdSGary Guo BStr: Index<Idx>, 325c07e67bdSGary Guo { 326c07e67bdSGary Guo type Output = <BStr as Index<Idx>>::Output; 327c07e67bdSGary Guo 328c07e67bdSGary Guo #[inline] index(&self, index: Idx) -> &Self::Output329c07e67bdSGary Guo fn index(&self, index: Idx) -> &Self::Output { 330c07e67bdSGary Guo &self.as_bytes()[index] 331c07e67bdSGary Guo } 332c07e67bdSGary Guo } 333c07e67bdSGary Guo 334b18cb00eSGary Guo /// Creates a new [`CStr`] from a string literal. 335b18cb00eSGary Guo /// 336b18cb00eSGary Guo /// The string literal should not contain any `NUL` bytes. 337b18cb00eSGary Guo /// 338b18cb00eSGary Guo /// # Examples 339b18cb00eSGary Guo /// 340b18cb00eSGary Guo /// ``` 341b18cb00eSGary Guo /// # use kernel::c_str; 342b18cb00eSGary Guo /// # use kernel::str::CStr; 343b18cb00eSGary Guo /// const MY_CSTR: &CStr = c_str!("My awesome CStr!"); 344b18cb00eSGary Guo /// ``` 345b18cb00eSGary Guo #[macro_export] 346b18cb00eSGary Guo macro_rules! c_str { 347b18cb00eSGary Guo ($str:expr) => {{ 348b18cb00eSGary Guo const S: &str = concat!($str, "\0"); 349b18cb00eSGary Guo const C: &$crate::str::CStr = match $crate::str::CStr::from_bytes_with_nul(S.as_bytes()) { 350b18cb00eSGary Guo Ok(v) => v, 351b18cb00eSGary Guo Err(_) => panic!("string contains interior NUL"), 352b18cb00eSGary Guo }; 353b18cb00eSGary Guo C 354b18cb00eSGary Guo }}; 355b18cb00eSGary Guo } 356b18cb00eSGary Guo 357985f1f09SMilan Landaverde #[cfg(test)] 358985f1f09SMilan Landaverde mod tests { 359985f1f09SMilan Landaverde use super::*; 360985f1f09SMilan Landaverde 361985f1f09SMilan Landaverde #[test] test_cstr_to_str()362985f1f09SMilan Landaverde fn test_cstr_to_str() { 363985f1f09SMilan Landaverde let good_bytes = b"\xf0\x9f\xa6\x80\0"; 364985f1f09SMilan Landaverde let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap(); 365985f1f09SMilan Landaverde let checked_str = checked_cstr.to_str().unwrap(); 366985f1f09SMilan Landaverde assert_eq!(checked_str, ""); 367985f1f09SMilan Landaverde } 368985f1f09SMilan Landaverde 369985f1f09SMilan Landaverde #[test] 370985f1f09SMilan Landaverde #[should_panic] test_cstr_to_str_panic()371985f1f09SMilan Landaverde fn test_cstr_to_str_panic() { 372985f1f09SMilan Landaverde let bad_bytes = b"\xc3\x28\0"; 373985f1f09SMilan Landaverde let checked_cstr = CStr::from_bytes_with_nul(bad_bytes).unwrap(); 374985f1f09SMilan Landaverde checked_cstr.to_str().unwrap(); 375985f1f09SMilan Landaverde } 376985f1f09SMilan Landaverde 377985f1f09SMilan Landaverde #[test] test_cstr_as_str_unchecked()378985f1f09SMilan Landaverde fn test_cstr_as_str_unchecked() { 379985f1f09SMilan Landaverde let good_bytes = b"\xf0\x9f\x90\xA7\0"; 380985f1f09SMilan Landaverde let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap(); 381985f1f09SMilan Landaverde let unchecked_str = unsafe { checked_cstr.as_str_unchecked() }; 382985f1f09SMilan Landaverde assert_eq!(unchecked_str, ""); 383985f1f09SMilan Landaverde } 384985f1f09SMilan Landaverde } 385985f1f09SMilan Landaverde 386247b365dSWedson Almeida Filho /// Allows formatting of [`fmt::Arguments`] into a raw buffer. 387247b365dSWedson Almeida Filho /// 388247b365dSWedson Almeida Filho /// It does not fail if callers write past the end of the buffer so that they can calculate the 389247b365dSWedson Almeida Filho /// size required to fit everything. 390247b365dSWedson Almeida Filho /// 391247b365dSWedson Almeida Filho /// # Invariants 392247b365dSWedson Almeida Filho /// 393247b365dSWedson Almeida Filho /// The memory region between `pos` (inclusive) and `end` (exclusive) is valid for writes if `pos` 394247b365dSWedson Almeida Filho /// is less than `end`. 395247b365dSWedson Almeida Filho pub(crate) struct RawFormatter { 396247b365dSWedson Almeida Filho // Use `usize` to use `saturating_*` functions. 397247b365dSWedson Almeida Filho beg: usize, 398247b365dSWedson Almeida Filho pos: usize, 399247b365dSWedson Almeida Filho end: usize, 400247b365dSWedson Almeida Filho } 401247b365dSWedson Almeida Filho 402247b365dSWedson Almeida Filho impl RawFormatter { 40365e1e497SWedson Almeida Filho /// Creates a new instance of [`RawFormatter`] with an empty buffer. new() -> Self40465e1e497SWedson Almeida Filho fn new() -> Self { 40565e1e497SWedson Almeida Filho // INVARIANT: The buffer is empty, so the region that needs to be writable is empty. 40665e1e497SWedson Almeida Filho Self { 40765e1e497SWedson Almeida Filho beg: 0, 40865e1e497SWedson Almeida Filho pos: 0, 40965e1e497SWedson Almeida Filho end: 0, 41065e1e497SWedson Almeida Filho } 41165e1e497SWedson Almeida Filho } 41265e1e497SWedson Almeida Filho 413247b365dSWedson Almeida Filho /// Creates a new instance of [`RawFormatter`] with the given buffer pointers. 414247b365dSWedson Almeida Filho /// 415247b365dSWedson Almeida Filho /// # Safety 416247b365dSWedson Almeida Filho /// 417247b365dSWedson Almeida Filho /// If `pos` is less than `end`, then the region between `pos` (inclusive) and `end` 418247b365dSWedson Almeida Filho /// (exclusive) must be valid for writes for the lifetime of the returned [`RawFormatter`]. from_ptrs(pos: *mut u8, end: *mut u8) -> Self419247b365dSWedson Almeida Filho pub(crate) unsafe fn from_ptrs(pos: *mut u8, end: *mut u8) -> Self { 42088e8c2ecSPatrick Blass // INVARIANT: The safety requirements guarantee the type invariants. 421247b365dSWedson Almeida Filho Self { 422247b365dSWedson Almeida Filho beg: pos as _, 423247b365dSWedson Almeida Filho pos: pos as _, 424247b365dSWedson Almeida Filho end: end as _, 425247b365dSWedson Almeida Filho } 426247b365dSWedson Almeida Filho } 427247b365dSWedson Almeida Filho 428fffed679SWedson Almeida Filho /// Creates a new instance of [`RawFormatter`] with the given buffer. 429fffed679SWedson Almeida Filho /// 430fffed679SWedson Almeida Filho /// # Safety 431fffed679SWedson Almeida Filho /// 432fffed679SWedson Almeida Filho /// The memory region starting at `buf` and extending for `len` bytes must be valid for writes 433fffed679SWedson Almeida Filho /// for the lifetime of the returned [`RawFormatter`]. from_buffer(buf: *mut u8, len: usize) -> Self434fffed679SWedson Almeida Filho pub(crate) unsafe fn from_buffer(buf: *mut u8, len: usize) -> Self { 435fffed679SWedson Almeida Filho let pos = buf as usize; 436fffed679SWedson Almeida Filho // INVARIANT: We ensure that `end` is never less then `buf`, and the safety requirements 437fffed679SWedson Almeida Filho // guarantees that the memory region is valid for writes. 438fffed679SWedson Almeida Filho Self { 439fffed679SWedson Almeida Filho pos, 440fffed679SWedson Almeida Filho beg: pos, 441fffed679SWedson Almeida Filho end: pos.saturating_add(len), 442fffed679SWedson Almeida Filho } 443fffed679SWedson Almeida Filho } 444fffed679SWedson Almeida Filho 445247b365dSWedson Almeida Filho /// Returns the current insert position. 446247b365dSWedson Almeida Filho /// 447247b365dSWedson Almeida Filho /// N.B. It may point to invalid memory. pos(&self) -> *mut u8448247b365dSWedson Almeida Filho pub(crate) fn pos(&self) -> *mut u8 { 449247b365dSWedson Almeida Filho self.pos as _ 450247b365dSWedson Almeida Filho } 45165e1e497SWedson Almeida Filho 45265e1e497SWedson Almeida Filho /// Return the number of bytes written to the formatter. bytes_written(&self) -> usize45365e1e497SWedson Almeida Filho pub(crate) fn bytes_written(&self) -> usize { 45465e1e497SWedson Almeida Filho self.pos - self.beg 45565e1e497SWedson Almeida Filho } 456247b365dSWedson Almeida Filho } 457247b365dSWedson Almeida Filho 458247b365dSWedson Almeida Filho impl fmt::Write for RawFormatter { write_str(&mut self, s: &str) -> fmt::Result459247b365dSWedson Almeida Filho fn write_str(&mut self, s: &str) -> fmt::Result { 460247b365dSWedson Almeida Filho // `pos` value after writing `len` bytes. This does not have to be bounded by `end`, but we 461247b365dSWedson Almeida Filho // don't want it to wrap around to 0. 462247b365dSWedson Almeida Filho let pos_new = self.pos.saturating_add(s.len()); 463247b365dSWedson Almeida Filho 464247b365dSWedson Almeida Filho // Amount that we can copy. `saturating_sub` ensures we get 0 if `pos` goes past `end`. 465247b365dSWedson Almeida Filho let len_to_copy = core::cmp::min(pos_new, self.end).saturating_sub(self.pos); 466247b365dSWedson Almeida Filho 467247b365dSWedson Almeida Filho if len_to_copy > 0 { 468247b365dSWedson Almeida Filho // SAFETY: If `len_to_copy` is non-zero, then we know `pos` has not gone past `end` 469247b365dSWedson Almeida Filho // yet, so it is valid for write per the type invariants. 470247b365dSWedson Almeida Filho unsafe { 471247b365dSWedson Almeida Filho core::ptr::copy_nonoverlapping( 472247b365dSWedson Almeida Filho s.as_bytes().as_ptr(), 473247b365dSWedson Almeida Filho self.pos as *mut u8, 474247b365dSWedson Almeida Filho len_to_copy, 475247b365dSWedson Almeida Filho ) 476247b365dSWedson Almeida Filho }; 477247b365dSWedson Almeida Filho } 478247b365dSWedson Almeida Filho 479247b365dSWedson Almeida Filho self.pos = pos_new; 480247b365dSWedson Almeida Filho Ok(()) 481247b365dSWedson Almeida Filho } 482247b365dSWedson Almeida Filho } 483fffed679SWedson Almeida Filho 484fffed679SWedson Almeida Filho /// Allows formatting of [`fmt::Arguments`] into a raw buffer. 485fffed679SWedson Almeida Filho /// 486fffed679SWedson Almeida Filho /// Fails if callers attempt to write more than will fit in the buffer. 487fffed679SWedson Almeida Filho pub(crate) struct Formatter(RawFormatter); 488fffed679SWedson Almeida Filho 489fffed679SWedson Almeida Filho impl Formatter { 490fffed679SWedson Almeida Filho /// Creates a new instance of [`Formatter`] with the given buffer. 491fffed679SWedson Almeida Filho /// 492fffed679SWedson Almeida Filho /// # Safety 493fffed679SWedson Almeida Filho /// 494fffed679SWedson Almeida Filho /// The memory region starting at `buf` and extending for `len` bytes must be valid for writes 495fffed679SWedson Almeida Filho /// for the lifetime of the returned [`Formatter`]. from_buffer(buf: *mut u8, len: usize) -> Self496fffed679SWedson Almeida Filho pub(crate) unsafe fn from_buffer(buf: *mut u8, len: usize) -> Self { 497fffed679SWedson Almeida Filho // SAFETY: The safety requirements of this function satisfy those of the callee. 498fffed679SWedson Almeida Filho Self(unsafe { RawFormatter::from_buffer(buf, len) }) 499fffed679SWedson Almeida Filho } 500fffed679SWedson Almeida Filho } 501fffed679SWedson Almeida Filho 502fffed679SWedson Almeida Filho impl Deref for Formatter { 503fffed679SWedson Almeida Filho type Target = RawFormatter; 504fffed679SWedson Almeida Filho deref(&self) -> &Self::Target505fffed679SWedson Almeida Filho fn deref(&self) -> &Self::Target { 506fffed679SWedson Almeida Filho &self.0 507fffed679SWedson Almeida Filho } 508fffed679SWedson Almeida Filho } 509fffed679SWedson Almeida Filho 510fffed679SWedson Almeida Filho impl fmt::Write for Formatter { write_str(&mut self, s: &str) -> fmt::Result511fffed679SWedson Almeida Filho fn write_str(&mut self, s: &str) -> fmt::Result { 512fffed679SWedson Almeida Filho self.0.write_str(s)?; 513fffed679SWedson Almeida Filho 514fffed679SWedson Almeida Filho // Fail the request if we go past the end of the buffer. 515fffed679SWedson Almeida Filho if self.0.pos > self.0.end { 516fffed679SWedson Almeida Filho Err(fmt::Error) 517fffed679SWedson Almeida Filho } else { 518fffed679SWedson Almeida Filho Ok(()) 519fffed679SWedson Almeida Filho } 520fffed679SWedson Almeida Filho } 521fffed679SWedson Almeida Filho } 52265e1e497SWedson Almeida Filho 52365e1e497SWedson Almeida Filho /// An owned string that is guaranteed to have exactly one `NUL` byte, which is at the end. 52465e1e497SWedson Almeida Filho /// 52565e1e497SWedson Almeida Filho /// Used for interoperability with kernel APIs that take C strings. 52665e1e497SWedson Almeida Filho /// 52765e1e497SWedson Almeida Filho /// # Invariants 52865e1e497SWedson Almeida Filho /// 52965e1e497SWedson Almeida Filho /// The string is always `NUL`-terminated and contains no other `NUL` bytes. 53065e1e497SWedson Almeida Filho /// 53165e1e497SWedson Almeida Filho /// # Examples 53265e1e497SWedson Almeida Filho /// 53365e1e497SWedson Almeida Filho /// ``` 534*cf36a495SMiguel Ojeda /// use kernel::{str::CString, fmt}; 53565e1e497SWedson Almeida Filho /// 53665e1e497SWedson Almeida Filho /// let s = CString::try_from_fmt(fmt!("{}{}{}", "abc", 10, 20)).unwrap(); 53765e1e497SWedson Almeida Filho /// assert_eq!(s.as_bytes_with_nul(), "abc1020\0".as_bytes()); 53865e1e497SWedson Almeida Filho /// 53965e1e497SWedson Almeida Filho /// let tmp = "testing"; 54065e1e497SWedson Almeida Filho /// let s = CString::try_from_fmt(fmt!("{tmp}{}", 123)).unwrap(); 54165e1e497SWedson Almeida Filho /// assert_eq!(s.as_bytes_with_nul(), "testing123\0".as_bytes()); 54265e1e497SWedson Almeida Filho /// 54365e1e497SWedson Almeida Filho /// // This fails because it has an embedded `NUL` byte. 54465e1e497SWedson Almeida Filho /// let s = CString::try_from_fmt(fmt!("a\0b{}", 123)); 54565e1e497SWedson Almeida Filho /// assert_eq!(s.is_ok(), false); 54665e1e497SWedson Almeida Filho /// ``` 54765e1e497SWedson Almeida Filho pub struct CString { 54865e1e497SWedson Almeida Filho buf: Vec<u8>, 54965e1e497SWedson Almeida Filho } 55065e1e497SWedson Almeida Filho 55165e1e497SWedson Almeida Filho impl CString { 55265e1e497SWedson Almeida Filho /// Creates an instance of [`CString`] from the given formatted arguments. try_from_fmt(args: fmt::Arguments<'_>) -> Result<Self, Error>55365e1e497SWedson Almeida Filho pub fn try_from_fmt(args: fmt::Arguments<'_>) -> Result<Self, Error> { 55465e1e497SWedson Almeida Filho // Calculate the size needed (formatted string plus `NUL` terminator). 55565e1e497SWedson Almeida Filho let mut f = RawFormatter::new(); 55665e1e497SWedson Almeida Filho f.write_fmt(args)?; 55765e1e497SWedson Almeida Filho f.write_str("\0")?; 55865e1e497SWedson Almeida Filho let size = f.bytes_written(); 55965e1e497SWedson Almeida Filho 56065e1e497SWedson Almeida Filho // Allocate a vector with the required number of bytes, and write to it. 56165e1e497SWedson Almeida Filho let mut buf = Vec::try_with_capacity(size)?; 56265e1e497SWedson Almeida Filho // SAFETY: The buffer stored in `buf` is at least of size `size` and is valid for writes. 56365e1e497SWedson Almeida Filho let mut f = unsafe { Formatter::from_buffer(buf.as_mut_ptr(), size) }; 56465e1e497SWedson Almeida Filho f.write_fmt(args)?; 56565e1e497SWedson Almeida Filho f.write_str("\0")?; 56665e1e497SWedson Almeida Filho 56765e1e497SWedson Almeida Filho // SAFETY: The number of bytes that can be written to `f` is bounded by `size`, which is 56865e1e497SWedson Almeida Filho // `buf`'s capacity. The contents of the buffer have been initialised by writes to `f`. 56965e1e497SWedson Almeida Filho unsafe { buf.set_len(f.bytes_written()) }; 57065e1e497SWedson Almeida Filho 57165e1e497SWedson Almeida Filho // Check that there are no `NUL` bytes before the end. 57265e1e497SWedson Almeida Filho // SAFETY: The buffer is valid for read because `f.bytes_written()` is bounded by `size` 57365e1e497SWedson Almeida Filho // (which the minimum buffer size) and is non-zero (we wrote at least the `NUL` terminator) 57465e1e497SWedson Almeida Filho // so `f.bytes_written() - 1` doesn't underflow. 57565e1e497SWedson Almeida Filho let ptr = unsafe { bindings::memchr(buf.as_ptr().cast(), 0, (f.bytes_written() - 1) as _) }; 57665e1e497SWedson Almeida Filho if !ptr.is_null() { 57765e1e497SWedson Almeida Filho return Err(EINVAL); 57865e1e497SWedson Almeida Filho } 57965e1e497SWedson Almeida Filho 58065e1e497SWedson Almeida Filho // INVARIANT: We wrote the `NUL` terminator and checked above that no other `NUL` bytes 58165e1e497SWedson Almeida Filho // exist in the buffer. 58265e1e497SWedson Almeida Filho Ok(Self { buf }) 58365e1e497SWedson Almeida Filho } 58465e1e497SWedson Almeida Filho } 58565e1e497SWedson Almeida Filho 58665e1e497SWedson Almeida Filho impl Deref for CString { 58765e1e497SWedson Almeida Filho type Target = CStr; 58865e1e497SWedson Almeida Filho deref(&self) -> &Self::Target58965e1e497SWedson Almeida Filho fn deref(&self) -> &Self::Target { 59065e1e497SWedson Almeida Filho // SAFETY: The type invariants guarantee that the string is `NUL`-terminated and that no 59165e1e497SWedson Almeida Filho // other `NUL` bytes exist. 59265e1e497SWedson Almeida Filho unsafe { CStr::from_bytes_with_nul_unchecked(self.buf.as_slice()) } 59365e1e497SWedson Almeida Filho } 59465e1e497SWedson Almeida Filho } 595ef320549SWedson Almeida Filho 59666bd7533SAlice Ryhl impl<'a> TryFrom<&'a CStr> for CString { 59766bd7533SAlice Ryhl type Error = AllocError; 59866bd7533SAlice Ryhl try_from(cstr: &'a CStr) -> Result<CString, AllocError>59966bd7533SAlice Ryhl fn try_from(cstr: &'a CStr) -> Result<CString, AllocError> { 60066bd7533SAlice Ryhl let mut buf = Vec::new(); 60166bd7533SAlice Ryhl 60266bd7533SAlice Ryhl buf.try_extend_from_slice(cstr.as_bytes_with_nul()) 60366bd7533SAlice Ryhl .map_err(|_| AllocError)?; 60466bd7533SAlice Ryhl 60566bd7533SAlice Ryhl // INVARIANT: The `CStr` and `CString` types have the same invariants for 60666bd7533SAlice Ryhl // the string data, and we copied it over without changes. 60766bd7533SAlice Ryhl Ok(CString { buf }) 60866bd7533SAlice Ryhl } 60966bd7533SAlice Ryhl } 61066bd7533SAlice Ryhl 611ef320549SWedson Almeida Filho /// A convenience alias for [`core::format_args`]. 612ef320549SWedson Almeida Filho #[macro_export] 613ef320549SWedson Almeida Filho macro_rules! fmt { 614ef320549SWedson Almeida Filho ($($f:tt)*) => ( core::format_args!($($f)*) ) 615ef320549SWedson Almeida Filho } 616