1247b365dSWedson Almeida Filho // SPDX-License-Identifier: GPL-2.0 2247b365dSWedson Almeida Filho 3247b365dSWedson Almeida Filho //! String representations. 4247b365dSWedson Almeida Filho 5*65e1e497SWedson Almeida Filho use alloc::vec::Vec; 6c07e67bdSGary Guo use core::fmt::{self, Write}; 7c07e67bdSGary Guo use core::ops::{self, Deref, Index}; 8247b365dSWedson Almeida Filho 9d126d238SGary Guo use crate::{ 10d126d238SGary Guo bindings, 11d126d238SGary Guo error::{code::*, Error}, 12d126d238SGary Guo }; 13d126d238SGary Guo 147c597746SGary Guo /// Byte string without UTF-8 validity guarantee. 157c597746SGary Guo /// 167c597746SGary Guo /// `BStr` is simply an alias to `[u8]`, but has a more evident semantical meaning. 177c597746SGary Guo pub type BStr = [u8]; 187c597746SGary Guo 19650ec515SGary Guo /// Creates a new [`BStr`] from a string literal. 20650ec515SGary Guo /// 21650ec515SGary Guo /// `b_str!` converts the supplied string literal to byte string, so non-ASCII 22650ec515SGary Guo /// characters can be included. 23650ec515SGary Guo /// 24650ec515SGary Guo /// # Examples 25650ec515SGary Guo /// 26650ec515SGary Guo /// ``` 27650ec515SGary Guo /// # use kernel::b_str; 28650ec515SGary Guo /// # use kernel::str::BStr; 29650ec515SGary Guo /// const MY_BSTR: &BStr = b_str!("My awesome BStr!"); 30650ec515SGary Guo /// ``` 31650ec515SGary Guo #[macro_export] 32650ec515SGary Guo macro_rules! b_str { 33650ec515SGary Guo ($str:literal) => {{ 34650ec515SGary Guo const S: &'static str = $str; 35650ec515SGary Guo const C: &'static $crate::str::BStr = S.as_bytes(); 36650ec515SGary Guo C 37650ec515SGary Guo }}; 38650ec515SGary Guo } 39650ec515SGary Guo 40d126d238SGary Guo /// Possible errors when using conversion functions in [`CStr`]. 41d126d238SGary Guo #[derive(Debug, Clone, Copy)] 42d126d238SGary Guo pub enum CStrConvertError { 43d126d238SGary Guo /// Supplied bytes contain an interior `NUL`. 44d126d238SGary Guo InteriorNul, 45d126d238SGary Guo 46d126d238SGary Guo /// Supplied bytes are not terminated by `NUL`. 47d126d238SGary Guo NotNulTerminated, 48d126d238SGary Guo } 49d126d238SGary Guo 50d126d238SGary Guo impl From<CStrConvertError> for Error { 51d126d238SGary Guo #[inline] 52d126d238SGary Guo fn from(_: CStrConvertError) -> Error { 53d126d238SGary Guo EINVAL 54d126d238SGary Guo } 55d126d238SGary Guo } 56d126d238SGary Guo 57d126d238SGary Guo /// A string that is guaranteed to have exactly one `NUL` byte, which is at the 58d126d238SGary Guo /// end. 59d126d238SGary Guo /// 60d126d238SGary Guo /// Used for interoperability with kernel APIs that take C strings. 61d126d238SGary Guo #[repr(transparent)] 62d126d238SGary Guo pub struct CStr([u8]); 63d126d238SGary Guo 64d126d238SGary Guo impl CStr { 65d126d238SGary Guo /// Returns the length of this string excluding `NUL`. 66d126d238SGary Guo #[inline] 67d126d238SGary Guo pub const fn len(&self) -> usize { 68d126d238SGary Guo self.len_with_nul() - 1 69d126d238SGary Guo } 70d126d238SGary Guo 71d126d238SGary Guo /// Returns the length of this string with `NUL`. 72d126d238SGary Guo #[inline] 73d126d238SGary Guo pub const fn len_with_nul(&self) -> usize { 74d126d238SGary Guo // SAFETY: This is one of the invariant of `CStr`. 75d126d238SGary Guo // We add a `unreachable_unchecked` here to hint the optimizer that 76d126d238SGary Guo // the value returned from this function is non-zero. 77d126d238SGary Guo if self.0.is_empty() { 78d126d238SGary Guo unsafe { core::hint::unreachable_unchecked() }; 79d126d238SGary Guo } 80d126d238SGary Guo self.0.len() 81d126d238SGary Guo } 82d126d238SGary Guo 83d126d238SGary Guo /// Returns `true` if the string only includes `NUL`. 84d126d238SGary Guo #[inline] 85d126d238SGary Guo pub const fn is_empty(&self) -> bool { 86d126d238SGary Guo self.len() == 0 87d126d238SGary Guo } 88d126d238SGary Guo 89d126d238SGary Guo /// Wraps a raw C string pointer. 90d126d238SGary Guo /// 91d126d238SGary Guo /// # Safety 92d126d238SGary Guo /// 93d126d238SGary Guo /// `ptr` must be a valid pointer to a `NUL`-terminated C string, and it must 94d126d238SGary Guo /// last at least `'a`. When `CStr` is alive, the memory pointed by `ptr` 95d126d238SGary Guo /// must not be mutated. 96d126d238SGary Guo #[inline] 97d126d238SGary Guo pub unsafe fn from_char_ptr<'a>(ptr: *const core::ffi::c_char) -> &'a Self { 98d126d238SGary Guo // SAFETY: The safety precondition guarantees `ptr` is a valid pointer 99d126d238SGary Guo // to a `NUL`-terminated C string. 100d126d238SGary Guo let len = unsafe { bindings::strlen(ptr) } + 1; 101d126d238SGary Guo // SAFETY: Lifetime guaranteed by the safety precondition. 102d126d238SGary Guo let bytes = unsafe { core::slice::from_raw_parts(ptr as _, len as _) }; 103d126d238SGary Guo // SAFETY: As `len` is returned by `strlen`, `bytes` does not contain interior `NUL`. 104d126d238SGary Guo // As we have added 1 to `len`, the last byte is known to be `NUL`. 105d126d238SGary Guo unsafe { Self::from_bytes_with_nul_unchecked(bytes) } 106d126d238SGary Guo } 107d126d238SGary Guo 108d126d238SGary Guo /// Creates a [`CStr`] from a `[u8]`. 109d126d238SGary Guo /// 110d126d238SGary Guo /// The provided slice must be `NUL`-terminated, does not contain any 111d126d238SGary Guo /// interior `NUL` bytes. 112d126d238SGary Guo pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, CStrConvertError> { 113d126d238SGary Guo if bytes.is_empty() { 114d126d238SGary Guo return Err(CStrConvertError::NotNulTerminated); 115d126d238SGary Guo } 116d126d238SGary Guo if bytes[bytes.len() - 1] != 0 { 117d126d238SGary Guo return Err(CStrConvertError::NotNulTerminated); 118d126d238SGary Guo } 119d126d238SGary Guo let mut i = 0; 120d126d238SGary Guo // `i + 1 < bytes.len()` allows LLVM to optimize away bounds checking, 121d126d238SGary Guo // while it couldn't optimize away bounds checks for `i < bytes.len() - 1`. 122d126d238SGary Guo while i + 1 < bytes.len() { 123d126d238SGary Guo if bytes[i] == 0 { 124d126d238SGary Guo return Err(CStrConvertError::InteriorNul); 125d126d238SGary Guo } 126d126d238SGary Guo i += 1; 127d126d238SGary Guo } 128d126d238SGary Guo // SAFETY: We just checked that all properties hold. 129d126d238SGary Guo Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) }) 130d126d238SGary Guo } 131d126d238SGary Guo 132d126d238SGary Guo /// Creates a [`CStr`] from a `[u8]` without performing any additional 133d126d238SGary Guo /// checks. 134d126d238SGary Guo /// 135d126d238SGary Guo /// # Safety 136d126d238SGary Guo /// 137d126d238SGary Guo /// `bytes` *must* end with a `NUL` byte, and should only have a single 138d126d238SGary Guo /// `NUL` byte (or the string will be truncated). 139d126d238SGary Guo #[inline] 140d126d238SGary Guo pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr { 141d126d238SGary Guo // SAFETY: Properties of `bytes` guaranteed by the safety precondition. 142d126d238SGary Guo unsafe { core::mem::transmute(bytes) } 143d126d238SGary Guo } 144d126d238SGary Guo 145d126d238SGary Guo /// Returns a C pointer to the string. 146d126d238SGary Guo #[inline] 147d126d238SGary Guo pub const fn as_char_ptr(&self) -> *const core::ffi::c_char { 148d126d238SGary Guo self.0.as_ptr() as _ 149d126d238SGary Guo } 150d126d238SGary Guo 151d126d238SGary Guo /// Convert the string to a byte slice without the trailing 0 byte. 152d126d238SGary Guo #[inline] 153d126d238SGary Guo pub fn as_bytes(&self) -> &[u8] { 154d126d238SGary Guo &self.0[..self.len()] 155d126d238SGary Guo } 156d126d238SGary Guo 157d126d238SGary Guo /// Convert the string to a byte slice containing the trailing 0 byte. 158d126d238SGary Guo #[inline] 159d126d238SGary Guo pub const fn as_bytes_with_nul(&self) -> &[u8] { 160d126d238SGary Guo &self.0 161d126d238SGary Guo } 162d126d238SGary Guo 163d126d238SGary Guo /// Yields a [`&str`] slice if the [`CStr`] contains valid UTF-8. 164d126d238SGary Guo /// 165d126d238SGary Guo /// If the contents of the [`CStr`] are valid UTF-8 data, this 166d126d238SGary Guo /// function will return the corresponding [`&str`] slice. Otherwise, 167d126d238SGary Guo /// it will return an error with details of where UTF-8 validation failed. 168d126d238SGary Guo /// 169d126d238SGary Guo /// # Examples 170d126d238SGary Guo /// 171d126d238SGary Guo /// ``` 172d126d238SGary Guo /// # use kernel::str::CStr; 173d126d238SGary Guo /// let cstr = CStr::from_bytes_with_nul(b"foo\0").unwrap(); 174d126d238SGary Guo /// assert_eq!(cstr.to_str(), Ok("foo")); 175d126d238SGary Guo /// ``` 176d126d238SGary Guo #[inline] 177d126d238SGary Guo pub fn to_str(&self) -> Result<&str, core::str::Utf8Error> { 178d126d238SGary Guo core::str::from_utf8(self.as_bytes()) 179d126d238SGary Guo } 180d126d238SGary Guo 181d126d238SGary Guo /// Unsafely convert this [`CStr`] into a [`&str`], without checking for 182d126d238SGary Guo /// valid UTF-8. 183d126d238SGary Guo /// 184d126d238SGary Guo /// # Safety 185d126d238SGary Guo /// 186d126d238SGary Guo /// The contents must be valid UTF-8. 187d126d238SGary Guo /// 188d126d238SGary Guo /// # Examples 189d126d238SGary Guo /// 190d126d238SGary Guo /// ``` 191d126d238SGary Guo /// # use kernel::c_str; 192d126d238SGary Guo /// # use kernel::str::CStr; 193d126d238SGary Guo /// // SAFETY: String literals are guaranteed to be valid UTF-8 194d126d238SGary Guo /// // by the Rust compiler. 195d126d238SGary Guo /// let bar = c_str!("ツ"); 196d126d238SGary Guo /// assert_eq!(unsafe { bar.as_str_unchecked() }, "ツ"); 197d126d238SGary Guo /// ``` 198d126d238SGary Guo #[inline] 199d126d238SGary Guo pub unsafe fn as_str_unchecked(&self) -> &str { 200d126d238SGary Guo unsafe { core::str::from_utf8_unchecked(self.as_bytes()) } 201d126d238SGary Guo } 202d126d238SGary Guo } 203d126d238SGary Guo 204c07e67bdSGary Guo impl fmt::Display for CStr { 205c07e67bdSGary Guo /// Formats printable ASCII characters, escaping the rest. 206c07e67bdSGary Guo /// 207c07e67bdSGary Guo /// ``` 208c07e67bdSGary Guo /// # use kernel::c_str; 209c07e67bdSGary Guo /// # use kernel::str::CStr; 210c07e67bdSGary Guo /// # use kernel::str::CString; 211c07e67bdSGary Guo /// let penguin = c_str!(""); 212c07e67bdSGary Guo /// let s = CString::try_from_fmt(fmt!("{}", penguin)).unwrap(); 213c07e67bdSGary Guo /// assert_eq!(s.as_bytes_with_nul(), "\\xf0\\x9f\\x90\\xa7\0".as_bytes()); 214c07e67bdSGary Guo /// 215c07e67bdSGary Guo /// let ascii = c_str!("so \"cool\""); 216c07e67bdSGary Guo /// let s = CString::try_from_fmt(fmt!("{}", ascii)).unwrap(); 217c07e67bdSGary Guo /// assert_eq!(s.as_bytes_with_nul(), "so \"cool\"\0".as_bytes()); 218c07e67bdSGary Guo /// ``` 219c07e67bdSGary Guo fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 220c07e67bdSGary Guo for &c in self.as_bytes() { 221c07e67bdSGary Guo if (0x20..0x7f).contains(&c) { 222c07e67bdSGary Guo // Printable character. 223c07e67bdSGary Guo f.write_char(c as char)?; 224c07e67bdSGary Guo } else { 225c07e67bdSGary Guo write!(f, "\\x{:02x}", c)?; 226c07e67bdSGary Guo } 227c07e67bdSGary Guo } 228c07e67bdSGary Guo Ok(()) 229c07e67bdSGary Guo } 230c07e67bdSGary Guo } 231c07e67bdSGary Guo 232c07e67bdSGary Guo impl fmt::Debug for CStr { 233c07e67bdSGary Guo /// Formats printable ASCII characters with a double quote on either end, escaping the rest. 234c07e67bdSGary Guo /// 235c07e67bdSGary Guo /// ``` 236c07e67bdSGary Guo /// # use kernel::c_str; 237c07e67bdSGary Guo /// # use kernel::str::CStr; 238c07e67bdSGary Guo /// # use kernel::str::CString; 239c07e67bdSGary Guo /// let penguin = c_str!(""); 240c07e67bdSGary Guo /// let s = CString::try_from_fmt(fmt!("{:?}", penguin)).unwrap(); 241c07e67bdSGary Guo /// assert_eq!(s.as_bytes_with_nul(), "\"\\xf0\\x9f\\x90\\xa7\"\0".as_bytes()); 242c07e67bdSGary Guo /// 243c07e67bdSGary Guo /// // Embedded double quotes are escaped. 244c07e67bdSGary Guo /// let ascii = c_str!("so \"cool\""); 245c07e67bdSGary Guo /// let s = CString::try_from_fmt(fmt!("{:?}", ascii)).unwrap(); 246c07e67bdSGary Guo /// assert_eq!(s.as_bytes_with_nul(), "\"so \\\"cool\\\"\"\0".as_bytes()); 247c07e67bdSGary Guo /// ``` 248c07e67bdSGary Guo fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 249c07e67bdSGary Guo f.write_str("\"")?; 250c07e67bdSGary Guo for &c in self.as_bytes() { 251c07e67bdSGary Guo match c { 252c07e67bdSGary Guo // Printable characters. 253c07e67bdSGary Guo b'\"' => f.write_str("\\\"")?, 254c07e67bdSGary Guo 0x20..=0x7e => f.write_char(c as char)?, 255c07e67bdSGary Guo _ => write!(f, "\\x{:02x}", c)?, 256c07e67bdSGary Guo } 257c07e67bdSGary Guo } 258c07e67bdSGary Guo f.write_str("\"") 259c07e67bdSGary Guo } 260c07e67bdSGary Guo } 261c07e67bdSGary Guo 262c07e67bdSGary Guo impl AsRef<BStr> for CStr { 263c07e67bdSGary Guo #[inline] 264c07e67bdSGary Guo fn as_ref(&self) -> &BStr { 265c07e67bdSGary Guo self.as_bytes() 266c07e67bdSGary Guo } 267c07e67bdSGary Guo } 268c07e67bdSGary Guo 269c07e67bdSGary Guo impl Deref for CStr { 270c07e67bdSGary Guo type Target = BStr; 271c07e67bdSGary Guo 272c07e67bdSGary Guo #[inline] 273c07e67bdSGary Guo fn deref(&self) -> &Self::Target { 274c07e67bdSGary Guo self.as_bytes() 275c07e67bdSGary Guo } 276c07e67bdSGary Guo } 277c07e67bdSGary Guo 278c07e67bdSGary Guo impl Index<ops::RangeFrom<usize>> for CStr { 279c07e67bdSGary Guo type Output = CStr; 280c07e67bdSGary Guo 281c07e67bdSGary Guo #[inline] 282c07e67bdSGary Guo fn index(&self, index: ops::RangeFrom<usize>) -> &Self::Output { 283c07e67bdSGary Guo // Delegate bounds checking to slice. 284c07e67bdSGary Guo // Assign to _ to mute clippy's unnecessary operation warning. 285c07e67bdSGary Guo let _ = &self.as_bytes()[index.start..]; 286c07e67bdSGary Guo // SAFETY: We just checked the bounds. 287c07e67bdSGary Guo unsafe { Self::from_bytes_with_nul_unchecked(&self.0[index.start..]) } 288c07e67bdSGary Guo } 289c07e67bdSGary Guo } 290c07e67bdSGary Guo 291c07e67bdSGary Guo impl Index<ops::RangeFull> for CStr { 292c07e67bdSGary Guo type Output = CStr; 293c07e67bdSGary Guo 294c07e67bdSGary Guo #[inline] 295c07e67bdSGary Guo fn index(&self, _index: ops::RangeFull) -> &Self::Output { 296c07e67bdSGary Guo self 297c07e67bdSGary Guo } 298c07e67bdSGary Guo } 299c07e67bdSGary Guo 300c07e67bdSGary Guo mod private { 301c07e67bdSGary Guo use core::ops; 302c07e67bdSGary Guo 303c07e67bdSGary Guo // Marker trait for index types that can be forward to `BStr`. 304c07e67bdSGary Guo pub trait CStrIndex {} 305c07e67bdSGary Guo 306c07e67bdSGary Guo impl CStrIndex for usize {} 307c07e67bdSGary Guo impl CStrIndex for ops::Range<usize> {} 308c07e67bdSGary Guo impl CStrIndex for ops::RangeInclusive<usize> {} 309c07e67bdSGary Guo impl CStrIndex for ops::RangeToInclusive<usize> {} 310c07e67bdSGary Guo } 311c07e67bdSGary Guo 312c07e67bdSGary Guo impl<Idx> Index<Idx> for CStr 313c07e67bdSGary Guo where 314c07e67bdSGary Guo Idx: private::CStrIndex, 315c07e67bdSGary Guo BStr: Index<Idx>, 316c07e67bdSGary Guo { 317c07e67bdSGary Guo type Output = <BStr as Index<Idx>>::Output; 318c07e67bdSGary Guo 319c07e67bdSGary Guo #[inline] 320c07e67bdSGary Guo fn index(&self, index: Idx) -> &Self::Output { 321c07e67bdSGary Guo &self.as_bytes()[index] 322c07e67bdSGary Guo } 323c07e67bdSGary Guo } 324c07e67bdSGary Guo 325b18cb00eSGary Guo /// Creates a new [`CStr`] from a string literal. 326b18cb00eSGary Guo /// 327b18cb00eSGary Guo /// The string literal should not contain any `NUL` bytes. 328b18cb00eSGary Guo /// 329b18cb00eSGary Guo /// # Examples 330b18cb00eSGary Guo /// 331b18cb00eSGary Guo /// ``` 332b18cb00eSGary Guo /// # use kernel::c_str; 333b18cb00eSGary Guo /// # use kernel::str::CStr; 334b18cb00eSGary Guo /// const MY_CSTR: &CStr = c_str!("My awesome CStr!"); 335b18cb00eSGary Guo /// ``` 336b18cb00eSGary Guo #[macro_export] 337b18cb00eSGary Guo macro_rules! c_str { 338b18cb00eSGary Guo ($str:expr) => {{ 339b18cb00eSGary Guo const S: &str = concat!($str, "\0"); 340b18cb00eSGary Guo const C: &$crate::str::CStr = match $crate::str::CStr::from_bytes_with_nul(S.as_bytes()) { 341b18cb00eSGary Guo Ok(v) => v, 342b18cb00eSGary Guo Err(_) => panic!("string contains interior NUL"), 343b18cb00eSGary Guo }; 344b18cb00eSGary Guo C 345b18cb00eSGary Guo }}; 346b18cb00eSGary Guo } 347b18cb00eSGary Guo 348985f1f09SMilan Landaverde #[cfg(test)] 349985f1f09SMilan Landaverde mod tests { 350985f1f09SMilan Landaverde use super::*; 351985f1f09SMilan Landaverde 352985f1f09SMilan Landaverde #[test] 353985f1f09SMilan Landaverde fn test_cstr_to_str() { 354985f1f09SMilan Landaverde let good_bytes = b"\xf0\x9f\xa6\x80\0"; 355985f1f09SMilan Landaverde let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap(); 356985f1f09SMilan Landaverde let checked_str = checked_cstr.to_str().unwrap(); 357985f1f09SMilan Landaverde assert_eq!(checked_str, ""); 358985f1f09SMilan Landaverde } 359985f1f09SMilan Landaverde 360985f1f09SMilan Landaverde #[test] 361985f1f09SMilan Landaverde #[should_panic] 362985f1f09SMilan Landaverde fn test_cstr_to_str_panic() { 363985f1f09SMilan Landaverde let bad_bytes = b"\xc3\x28\0"; 364985f1f09SMilan Landaverde let checked_cstr = CStr::from_bytes_with_nul(bad_bytes).unwrap(); 365985f1f09SMilan Landaverde checked_cstr.to_str().unwrap(); 366985f1f09SMilan Landaverde } 367985f1f09SMilan Landaverde 368985f1f09SMilan Landaverde #[test] 369985f1f09SMilan Landaverde fn test_cstr_as_str_unchecked() { 370985f1f09SMilan Landaverde let good_bytes = b"\xf0\x9f\x90\xA7\0"; 371985f1f09SMilan Landaverde let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap(); 372985f1f09SMilan Landaverde let unchecked_str = unsafe { checked_cstr.as_str_unchecked() }; 373985f1f09SMilan Landaverde assert_eq!(unchecked_str, ""); 374985f1f09SMilan Landaverde } 375985f1f09SMilan Landaverde } 376985f1f09SMilan Landaverde 377247b365dSWedson Almeida Filho /// Allows formatting of [`fmt::Arguments`] into a raw buffer. 378247b365dSWedson Almeida Filho /// 379247b365dSWedson Almeida Filho /// It does not fail if callers write past the end of the buffer so that they can calculate the 380247b365dSWedson Almeida Filho /// size required to fit everything. 381247b365dSWedson Almeida Filho /// 382247b365dSWedson Almeida Filho /// # Invariants 383247b365dSWedson Almeida Filho /// 384247b365dSWedson Almeida Filho /// The memory region between `pos` (inclusive) and `end` (exclusive) is valid for writes if `pos` 385247b365dSWedson Almeida Filho /// is less than `end`. 386247b365dSWedson Almeida Filho pub(crate) struct RawFormatter { 387247b365dSWedson Almeida Filho // Use `usize` to use `saturating_*` functions. 388247b365dSWedson Almeida Filho beg: usize, 389247b365dSWedson Almeida Filho pos: usize, 390247b365dSWedson Almeida Filho end: usize, 391247b365dSWedson Almeida Filho } 392247b365dSWedson Almeida Filho 393247b365dSWedson Almeida Filho impl RawFormatter { 394*65e1e497SWedson Almeida Filho /// Creates a new instance of [`RawFormatter`] with an empty buffer. 395*65e1e497SWedson Almeida Filho fn new() -> Self { 396*65e1e497SWedson Almeida Filho // INVARIANT: The buffer is empty, so the region that needs to be writable is empty. 397*65e1e497SWedson Almeida Filho Self { 398*65e1e497SWedson Almeida Filho beg: 0, 399*65e1e497SWedson Almeida Filho pos: 0, 400*65e1e497SWedson Almeida Filho end: 0, 401*65e1e497SWedson Almeida Filho } 402*65e1e497SWedson Almeida Filho } 403*65e1e497SWedson Almeida Filho 404247b365dSWedson Almeida Filho /// Creates a new instance of [`RawFormatter`] with the given buffer pointers. 405247b365dSWedson Almeida Filho /// 406247b365dSWedson Almeida Filho /// # Safety 407247b365dSWedson Almeida Filho /// 408247b365dSWedson Almeida Filho /// If `pos` is less than `end`, then the region between `pos` (inclusive) and `end` 409247b365dSWedson Almeida Filho /// (exclusive) must be valid for writes for the lifetime of the returned [`RawFormatter`]. 410247b365dSWedson Almeida Filho pub(crate) unsafe fn from_ptrs(pos: *mut u8, end: *mut u8) -> Self { 411247b365dSWedson Almeida Filho // INVARIANT: The safety requierments guarantee the type invariants. 412247b365dSWedson Almeida Filho Self { 413247b365dSWedson Almeida Filho beg: pos as _, 414247b365dSWedson Almeida Filho pos: pos as _, 415247b365dSWedson Almeida Filho end: end as _, 416247b365dSWedson Almeida Filho } 417247b365dSWedson Almeida Filho } 418247b365dSWedson Almeida Filho 419fffed679SWedson Almeida Filho /// Creates a new instance of [`RawFormatter`] with the given buffer. 420fffed679SWedson Almeida Filho /// 421fffed679SWedson Almeida Filho /// # Safety 422fffed679SWedson Almeida Filho /// 423fffed679SWedson Almeida Filho /// The memory region starting at `buf` and extending for `len` bytes must be valid for writes 424fffed679SWedson Almeida Filho /// for the lifetime of the returned [`RawFormatter`]. 425fffed679SWedson Almeida Filho pub(crate) unsafe fn from_buffer(buf: *mut u8, len: usize) -> Self { 426fffed679SWedson Almeida Filho let pos = buf as usize; 427fffed679SWedson Almeida Filho // INVARIANT: We ensure that `end` is never less then `buf`, and the safety requirements 428fffed679SWedson Almeida Filho // guarantees that the memory region is valid for writes. 429fffed679SWedson Almeida Filho Self { 430fffed679SWedson Almeida Filho pos, 431fffed679SWedson Almeida Filho beg: pos, 432fffed679SWedson Almeida Filho end: pos.saturating_add(len), 433fffed679SWedson Almeida Filho } 434fffed679SWedson Almeida Filho } 435fffed679SWedson Almeida Filho 436247b365dSWedson Almeida Filho /// Returns the current insert position. 437247b365dSWedson Almeida Filho /// 438247b365dSWedson Almeida Filho /// N.B. It may point to invalid memory. 439247b365dSWedson Almeida Filho pub(crate) fn pos(&self) -> *mut u8 { 440247b365dSWedson Almeida Filho self.pos as _ 441247b365dSWedson Almeida Filho } 442*65e1e497SWedson Almeida Filho 443*65e1e497SWedson Almeida Filho /// Return the number of bytes written to the formatter. 444*65e1e497SWedson Almeida Filho pub(crate) fn bytes_written(&self) -> usize { 445*65e1e497SWedson Almeida Filho self.pos - self.beg 446*65e1e497SWedson Almeida Filho } 447247b365dSWedson Almeida Filho } 448247b365dSWedson Almeida Filho 449247b365dSWedson Almeida Filho impl fmt::Write for RawFormatter { 450247b365dSWedson Almeida Filho fn write_str(&mut self, s: &str) -> fmt::Result { 451247b365dSWedson Almeida Filho // `pos` value after writing `len` bytes. This does not have to be bounded by `end`, but we 452247b365dSWedson Almeida Filho // don't want it to wrap around to 0. 453247b365dSWedson Almeida Filho let pos_new = self.pos.saturating_add(s.len()); 454247b365dSWedson Almeida Filho 455247b365dSWedson Almeida Filho // Amount that we can copy. `saturating_sub` ensures we get 0 if `pos` goes past `end`. 456247b365dSWedson Almeida Filho let len_to_copy = core::cmp::min(pos_new, self.end).saturating_sub(self.pos); 457247b365dSWedson Almeida Filho 458247b365dSWedson Almeida Filho if len_to_copy > 0 { 459247b365dSWedson Almeida Filho // SAFETY: If `len_to_copy` is non-zero, then we know `pos` has not gone past `end` 460247b365dSWedson Almeida Filho // yet, so it is valid for write per the type invariants. 461247b365dSWedson Almeida Filho unsafe { 462247b365dSWedson Almeida Filho core::ptr::copy_nonoverlapping( 463247b365dSWedson Almeida Filho s.as_bytes().as_ptr(), 464247b365dSWedson Almeida Filho self.pos as *mut u8, 465247b365dSWedson Almeida Filho len_to_copy, 466247b365dSWedson Almeida Filho ) 467247b365dSWedson Almeida Filho }; 468247b365dSWedson Almeida Filho } 469247b365dSWedson Almeida Filho 470247b365dSWedson Almeida Filho self.pos = pos_new; 471247b365dSWedson Almeida Filho Ok(()) 472247b365dSWedson Almeida Filho } 473247b365dSWedson Almeida Filho } 474fffed679SWedson Almeida Filho 475fffed679SWedson Almeida Filho /// Allows formatting of [`fmt::Arguments`] into a raw buffer. 476fffed679SWedson Almeida Filho /// 477fffed679SWedson Almeida Filho /// Fails if callers attempt to write more than will fit in the buffer. 478fffed679SWedson Almeida Filho pub(crate) struct Formatter(RawFormatter); 479fffed679SWedson Almeida Filho 480fffed679SWedson Almeida Filho impl Formatter { 481fffed679SWedson Almeida Filho /// Creates a new instance of [`Formatter`] with the given buffer. 482fffed679SWedson Almeida Filho /// 483fffed679SWedson Almeida Filho /// # Safety 484fffed679SWedson Almeida Filho /// 485fffed679SWedson Almeida Filho /// The memory region starting at `buf` and extending for `len` bytes must be valid for writes 486fffed679SWedson Almeida Filho /// for the lifetime of the returned [`Formatter`]. 487fffed679SWedson Almeida Filho pub(crate) unsafe fn from_buffer(buf: *mut u8, len: usize) -> Self { 488fffed679SWedson Almeida Filho // SAFETY: The safety requirements of this function satisfy those of the callee. 489fffed679SWedson Almeida Filho Self(unsafe { RawFormatter::from_buffer(buf, len) }) 490fffed679SWedson Almeida Filho } 491fffed679SWedson Almeida Filho } 492fffed679SWedson Almeida Filho 493fffed679SWedson Almeida Filho impl Deref for Formatter { 494fffed679SWedson Almeida Filho type Target = RawFormatter; 495fffed679SWedson Almeida Filho 496fffed679SWedson Almeida Filho fn deref(&self) -> &Self::Target { 497fffed679SWedson Almeida Filho &self.0 498fffed679SWedson Almeida Filho } 499fffed679SWedson Almeida Filho } 500fffed679SWedson Almeida Filho 501fffed679SWedson Almeida Filho impl fmt::Write for Formatter { 502fffed679SWedson Almeida Filho fn write_str(&mut self, s: &str) -> fmt::Result { 503fffed679SWedson Almeida Filho self.0.write_str(s)?; 504fffed679SWedson Almeida Filho 505fffed679SWedson Almeida Filho // Fail the request if we go past the end of the buffer. 506fffed679SWedson Almeida Filho if self.0.pos > self.0.end { 507fffed679SWedson Almeida Filho Err(fmt::Error) 508fffed679SWedson Almeida Filho } else { 509fffed679SWedson Almeida Filho Ok(()) 510fffed679SWedson Almeida Filho } 511fffed679SWedson Almeida Filho } 512fffed679SWedson Almeida Filho } 513*65e1e497SWedson Almeida Filho 514*65e1e497SWedson Almeida Filho /// An owned string that is guaranteed to have exactly one `NUL` byte, which is at the end. 515*65e1e497SWedson Almeida Filho /// 516*65e1e497SWedson Almeida Filho /// Used for interoperability with kernel APIs that take C strings. 517*65e1e497SWedson Almeida Filho /// 518*65e1e497SWedson Almeida Filho /// # Invariants 519*65e1e497SWedson Almeida Filho /// 520*65e1e497SWedson Almeida Filho /// The string is always `NUL`-terminated and contains no other `NUL` bytes. 521*65e1e497SWedson Almeida Filho /// 522*65e1e497SWedson Almeida Filho /// # Examples 523*65e1e497SWedson Almeida Filho /// 524*65e1e497SWedson Almeida Filho /// ``` 525*65e1e497SWedson Almeida Filho /// use kernel::str::CString; 526*65e1e497SWedson Almeida Filho /// 527*65e1e497SWedson Almeida Filho /// let s = CString::try_from_fmt(fmt!("{}{}{}", "abc", 10, 20)).unwrap(); 528*65e1e497SWedson Almeida Filho /// assert_eq!(s.as_bytes_with_nul(), "abc1020\0".as_bytes()); 529*65e1e497SWedson Almeida Filho /// 530*65e1e497SWedson Almeida Filho /// let tmp = "testing"; 531*65e1e497SWedson Almeida Filho /// let s = CString::try_from_fmt(fmt!("{tmp}{}", 123)).unwrap(); 532*65e1e497SWedson Almeida Filho /// assert_eq!(s.as_bytes_with_nul(), "testing123\0".as_bytes()); 533*65e1e497SWedson Almeida Filho /// 534*65e1e497SWedson Almeida Filho /// // This fails because it has an embedded `NUL` byte. 535*65e1e497SWedson Almeida Filho /// let s = CString::try_from_fmt(fmt!("a\0b{}", 123)); 536*65e1e497SWedson Almeida Filho /// assert_eq!(s.is_ok(), false); 537*65e1e497SWedson Almeida Filho /// ``` 538*65e1e497SWedson Almeida Filho pub struct CString { 539*65e1e497SWedson Almeida Filho buf: Vec<u8>, 540*65e1e497SWedson Almeida Filho } 541*65e1e497SWedson Almeida Filho 542*65e1e497SWedson Almeida Filho impl CString { 543*65e1e497SWedson Almeida Filho /// Creates an instance of [`CString`] from the given formatted arguments. 544*65e1e497SWedson Almeida Filho pub fn try_from_fmt(args: fmt::Arguments<'_>) -> Result<Self, Error> { 545*65e1e497SWedson Almeida Filho // Calculate the size needed (formatted string plus `NUL` terminator). 546*65e1e497SWedson Almeida Filho let mut f = RawFormatter::new(); 547*65e1e497SWedson Almeida Filho f.write_fmt(args)?; 548*65e1e497SWedson Almeida Filho f.write_str("\0")?; 549*65e1e497SWedson Almeida Filho let size = f.bytes_written(); 550*65e1e497SWedson Almeida Filho 551*65e1e497SWedson Almeida Filho // Allocate a vector with the required number of bytes, and write to it. 552*65e1e497SWedson Almeida Filho let mut buf = Vec::try_with_capacity(size)?; 553*65e1e497SWedson Almeida Filho // SAFETY: The buffer stored in `buf` is at least of size `size` and is valid for writes. 554*65e1e497SWedson Almeida Filho let mut f = unsafe { Formatter::from_buffer(buf.as_mut_ptr(), size) }; 555*65e1e497SWedson Almeida Filho f.write_fmt(args)?; 556*65e1e497SWedson Almeida Filho f.write_str("\0")?; 557*65e1e497SWedson Almeida Filho 558*65e1e497SWedson Almeida Filho // SAFETY: The number of bytes that can be written to `f` is bounded by `size`, which is 559*65e1e497SWedson Almeida Filho // `buf`'s capacity. The contents of the buffer have been initialised by writes to `f`. 560*65e1e497SWedson Almeida Filho unsafe { buf.set_len(f.bytes_written()) }; 561*65e1e497SWedson Almeida Filho 562*65e1e497SWedson Almeida Filho // Check that there are no `NUL` bytes before the end. 563*65e1e497SWedson Almeida Filho // SAFETY: The buffer is valid for read because `f.bytes_written()` is bounded by `size` 564*65e1e497SWedson Almeida Filho // (which the minimum buffer size) and is non-zero (we wrote at least the `NUL` terminator) 565*65e1e497SWedson Almeida Filho // so `f.bytes_written() - 1` doesn't underflow. 566*65e1e497SWedson Almeida Filho let ptr = unsafe { bindings::memchr(buf.as_ptr().cast(), 0, (f.bytes_written() - 1) as _) }; 567*65e1e497SWedson Almeida Filho if !ptr.is_null() { 568*65e1e497SWedson Almeida Filho return Err(EINVAL); 569*65e1e497SWedson Almeida Filho } 570*65e1e497SWedson Almeida Filho 571*65e1e497SWedson Almeida Filho // INVARIANT: We wrote the `NUL` terminator and checked above that no other `NUL` bytes 572*65e1e497SWedson Almeida Filho // exist in the buffer. 573*65e1e497SWedson Almeida Filho Ok(Self { buf }) 574*65e1e497SWedson Almeida Filho } 575*65e1e497SWedson Almeida Filho } 576*65e1e497SWedson Almeida Filho 577*65e1e497SWedson Almeida Filho impl Deref for CString { 578*65e1e497SWedson Almeida Filho type Target = CStr; 579*65e1e497SWedson Almeida Filho 580*65e1e497SWedson Almeida Filho fn deref(&self) -> &Self::Target { 581*65e1e497SWedson Almeida Filho // SAFETY: The type invariants guarantee that the string is `NUL`-terminated and that no 582*65e1e497SWedson Almeida Filho // other `NUL` bytes exist. 583*65e1e497SWedson Almeida Filho unsafe { CStr::from_bytes_with_nul_unchecked(self.buf.as_slice()) } 584*65e1e497SWedson Almeida Filho } 585*65e1e497SWedson Almeida Filho } 586