1247b365dSWedson Almeida Filho // SPDX-License-Identifier: GPL-2.0 2247b365dSWedson Almeida Filho 3247b365dSWedson Almeida Filho //! String representations. 4247b365dSWedson Almeida Filho 5c07e67bdSGary Guo use core::fmt::{self, Write}; 6c07e67bdSGary Guo use core::ops::{self, Deref, Index}; 7247b365dSWedson Almeida Filho 8d126d238SGary Guo use crate::{ 9d126d238SGary Guo bindings, 10d126d238SGary Guo error::{code::*, Error}, 11d126d238SGary Guo }; 12d126d238SGary Guo 137c597746SGary Guo /// Byte string without UTF-8 validity guarantee. 147c597746SGary Guo /// 157c597746SGary Guo /// `BStr` is simply an alias to `[u8]`, but has a more evident semantical meaning. 167c597746SGary Guo pub type BStr = [u8]; 177c597746SGary Guo 18650ec515SGary Guo /// Creates a new [`BStr`] from a string literal. 19650ec515SGary Guo /// 20650ec515SGary Guo /// `b_str!` converts the supplied string literal to byte string, so non-ASCII 21650ec515SGary Guo /// characters can be included. 22650ec515SGary Guo /// 23650ec515SGary Guo /// # Examples 24650ec515SGary Guo /// 25650ec515SGary Guo /// ``` 26650ec515SGary Guo /// # use kernel::b_str; 27650ec515SGary Guo /// # use kernel::str::BStr; 28650ec515SGary Guo /// const MY_BSTR: &BStr = b_str!("My awesome BStr!"); 29650ec515SGary Guo /// ``` 30650ec515SGary Guo #[macro_export] 31650ec515SGary Guo macro_rules! b_str { 32650ec515SGary Guo ($str:literal) => {{ 33650ec515SGary Guo const S: &'static str = $str; 34650ec515SGary Guo const C: &'static $crate::str::BStr = S.as_bytes(); 35650ec515SGary Guo C 36650ec515SGary Guo }}; 37650ec515SGary Guo } 38650ec515SGary Guo 39d126d238SGary Guo /// Possible errors when using conversion functions in [`CStr`]. 40d126d238SGary Guo #[derive(Debug, Clone, Copy)] 41d126d238SGary Guo pub enum CStrConvertError { 42d126d238SGary Guo /// Supplied bytes contain an interior `NUL`. 43d126d238SGary Guo InteriorNul, 44d126d238SGary Guo 45d126d238SGary Guo /// Supplied bytes are not terminated by `NUL`. 46d126d238SGary Guo NotNulTerminated, 47d126d238SGary Guo } 48d126d238SGary Guo 49d126d238SGary Guo impl From<CStrConvertError> for Error { 50d126d238SGary Guo #[inline] 51d126d238SGary Guo fn from(_: CStrConvertError) -> Error { 52d126d238SGary Guo EINVAL 53d126d238SGary Guo } 54d126d238SGary Guo } 55d126d238SGary Guo 56d126d238SGary Guo /// A string that is guaranteed to have exactly one `NUL` byte, which is at the 57d126d238SGary Guo /// end. 58d126d238SGary Guo /// 59d126d238SGary Guo /// Used for interoperability with kernel APIs that take C strings. 60d126d238SGary Guo #[repr(transparent)] 61d126d238SGary Guo pub struct CStr([u8]); 62d126d238SGary Guo 63d126d238SGary Guo impl CStr { 64d126d238SGary Guo /// Returns the length of this string excluding `NUL`. 65d126d238SGary Guo #[inline] 66d126d238SGary Guo pub const fn len(&self) -> usize { 67d126d238SGary Guo self.len_with_nul() - 1 68d126d238SGary Guo } 69d126d238SGary Guo 70d126d238SGary Guo /// Returns the length of this string with `NUL`. 71d126d238SGary Guo #[inline] 72d126d238SGary Guo pub const fn len_with_nul(&self) -> usize { 73d126d238SGary Guo // SAFETY: This is one of the invariant of `CStr`. 74d126d238SGary Guo // We add a `unreachable_unchecked` here to hint the optimizer that 75d126d238SGary Guo // the value returned from this function is non-zero. 76d126d238SGary Guo if self.0.is_empty() { 77d126d238SGary Guo unsafe { core::hint::unreachable_unchecked() }; 78d126d238SGary Guo } 79d126d238SGary Guo self.0.len() 80d126d238SGary Guo } 81d126d238SGary Guo 82d126d238SGary Guo /// Returns `true` if the string only includes `NUL`. 83d126d238SGary Guo #[inline] 84d126d238SGary Guo pub const fn is_empty(&self) -> bool { 85d126d238SGary Guo self.len() == 0 86d126d238SGary Guo } 87d126d238SGary Guo 88d126d238SGary Guo /// Wraps a raw C string pointer. 89d126d238SGary Guo /// 90d126d238SGary Guo /// # Safety 91d126d238SGary Guo /// 92d126d238SGary Guo /// `ptr` must be a valid pointer to a `NUL`-terminated C string, and it must 93d126d238SGary Guo /// last at least `'a`. When `CStr` is alive, the memory pointed by `ptr` 94d126d238SGary Guo /// must not be mutated. 95d126d238SGary Guo #[inline] 96d126d238SGary Guo pub unsafe fn from_char_ptr<'a>(ptr: *const core::ffi::c_char) -> &'a Self { 97d126d238SGary Guo // SAFETY: The safety precondition guarantees `ptr` is a valid pointer 98d126d238SGary Guo // to a `NUL`-terminated C string. 99d126d238SGary Guo let len = unsafe { bindings::strlen(ptr) } + 1; 100d126d238SGary Guo // SAFETY: Lifetime guaranteed by the safety precondition. 101d126d238SGary Guo let bytes = unsafe { core::slice::from_raw_parts(ptr as _, len as _) }; 102d126d238SGary Guo // SAFETY: As `len` is returned by `strlen`, `bytes` does not contain interior `NUL`. 103d126d238SGary Guo // As we have added 1 to `len`, the last byte is known to be `NUL`. 104d126d238SGary Guo unsafe { Self::from_bytes_with_nul_unchecked(bytes) } 105d126d238SGary Guo } 106d126d238SGary Guo 107d126d238SGary Guo /// Creates a [`CStr`] from a `[u8]`. 108d126d238SGary Guo /// 109d126d238SGary Guo /// The provided slice must be `NUL`-terminated, does not contain any 110d126d238SGary Guo /// interior `NUL` bytes. 111d126d238SGary Guo pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, CStrConvertError> { 112d126d238SGary Guo if bytes.is_empty() { 113d126d238SGary Guo return Err(CStrConvertError::NotNulTerminated); 114d126d238SGary Guo } 115d126d238SGary Guo if bytes[bytes.len() - 1] != 0 { 116d126d238SGary Guo return Err(CStrConvertError::NotNulTerminated); 117d126d238SGary Guo } 118d126d238SGary Guo let mut i = 0; 119d126d238SGary Guo // `i + 1 < bytes.len()` allows LLVM to optimize away bounds checking, 120d126d238SGary Guo // while it couldn't optimize away bounds checks for `i < bytes.len() - 1`. 121d126d238SGary Guo while i + 1 < bytes.len() { 122d126d238SGary Guo if bytes[i] == 0 { 123d126d238SGary Guo return Err(CStrConvertError::InteriorNul); 124d126d238SGary Guo } 125d126d238SGary Guo i += 1; 126d126d238SGary Guo } 127d126d238SGary Guo // SAFETY: We just checked that all properties hold. 128d126d238SGary Guo Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) }) 129d126d238SGary Guo } 130d126d238SGary Guo 131d126d238SGary Guo /// Creates a [`CStr`] from a `[u8]` without performing any additional 132d126d238SGary Guo /// checks. 133d126d238SGary Guo /// 134d126d238SGary Guo /// # Safety 135d126d238SGary Guo /// 136d126d238SGary Guo /// `bytes` *must* end with a `NUL` byte, and should only have a single 137d126d238SGary Guo /// `NUL` byte (or the string will be truncated). 138d126d238SGary Guo #[inline] 139d126d238SGary Guo pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr { 140d126d238SGary Guo // SAFETY: Properties of `bytes` guaranteed by the safety precondition. 141d126d238SGary Guo unsafe { core::mem::transmute(bytes) } 142d126d238SGary Guo } 143d126d238SGary Guo 144d126d238SGary Guo /// Returns a C pointer to the string. 145d126d238SGary Guo #[inline] 146d126d238SGary Guo pub const fn as_char_ptr(&self) -> *const core::ffi::c_char { 147d126d238SGary Guo self.0.as_ptr() as _ 148d126d238SGary Guo } 149d126d238SGary Guo 150d126d238SGary Guo /// Convert the string to a byte slice without the trailing 0 byte. 151d126d238SGary Guo #[inline] 152d126d238SGary Guo pub fn as_bytes(&self) -> &[u8] { 153d126d238SGary Guo &self.0[..self.len()] 154d126d238SGary Guo } 155d126d238SGary Guo 156d126d238SGary Guo /// Convert the string to a byte slice containing the trailing 0 byte. 157d126d238SGary Guo #[inline] 158d126d238SGary Guo pub const fn as_bytes_with_nul(&self) -> &[u8] { 159d126d238SGary Guo &self.0 160d126d238SGary Guo } 161d126d238SGary Guo 162d126d238SGary Guo /// Yields a [`&str`] slice if the [`CStr`] contains valid UTF-8. 163d126d238SGary Guo /// 164d126d238SGary Guo /// If the contents of the [`CStr`] are valid UTF-8 data, this 165d126d238SGary Guo /// function will return the corresponding [`&str`] slice. Otherwise, 166d126d238SGary Guo /// it will return an error with details of where UTF-8 validation failed. 167d126d238SGary Guo /// 168d126d238SGary Guo /// # Examples 169d126d238SGary Guo /// 170d126d238SGary Guo /// ``` 171d126d238SGary Guo /// # use kernel::str::CStr; 172d126d238SGary Guo /// let cstr = CStr::from_bytes_with_nul(b"foo\0").unwrap(); 173d126d238SGary Guo /// assert_eq!(cstr.to_str(), Ok("foo")); 174d126d238SGary Guo /// ``` 175d126d238SGary Guo #[inline] 176d126d238SGary Guo pub fn to_str(&self) -> Result<&str, core::str::Utf8Error> { 177d126d238SGary Guo core::str::from_utf8(self.as_bytes()) 178d126d238SGary Guo } 179d126d238SGary Guo 180d126d238SGary Guo /// Unsafely convert this [`CStr`] into a [`&str`], without checking for 181d126d238SGary Guo /// valid UTF-8. 182d126d238SGary Guo /// 183d126d238SGary Guo /// # Safety 184d126d238SGary Guo /// 185d126d238SGary Guo /// The contents must be valid UTF-8. 186d126d238SGary Guo /// 187d126d238SGary Guo /// # Examples 188d126d238SGary Guo /// 189d126d238SGary Guo /// ``` 190d126d238SGary Guo /// # use kernel::c_str; 191d126d238SGary Guo /// # use kernel::str::CStr; 192d126d238SGary Guo /// // SAFETY: String literals are guaranteed to be valid UTF-8 193d126d238SGary Guo /// // by the Rust compiler. 194d126d238SGary Guo /// let bar = c_str!("ツ"); 195d126d238SGary Guo /// assert_eq!(unsafe { bar.as_str_unchecked() }, "ツ"); 196d126d238SGary Guo /// ``` 197d126d238SGary Guo #[inline] 198d126d238SGary Guo pub unsafe fn as_str_unchecked(&self) -> &str { 199d126d238SGary Guo unsafe { core::str::from_utf8_unchecked(self.as_bytes()) } 200d126d238SGary Guo } 201d126d238SGary Guo } 202d126d238SGary Guo 203c07e67bdSGary Guo impl fmt::Display for CStr { 204c07e67bdSGary Guo /// Formats printable ASCII characters, escaping the rest. 205c07e67bdSGary Guo /// 206c07e67bdSGary Guo /// ``` 207c07e67bdSGary Guo /// # use kernel::c_str; 208c07e67bdSGary Guo /// # use kernel::str::CStr; 209c07e67bdSGary Guo /// # use kernel::str::CString; 210c07e67bdSGary Guo /// let penguin = c_str!(""); 211c07e67bdSGary Guo /// let s = CString::try_from_fmt(fmt!("{}", penguin)).unwrap(); 212c07e67bdSGary Guo /// assert_eq!(s.as_bytes_with_nul(), "\\xf0\\x9f\\x90\\xa7\0".as_bytes()); 213c07e67bdSGary Guo /// 214c07e67bdSGary Guo /// let ascii = c_str!("so \"cool\""); 215c07e67bdSGary Guo /// let s = CString::try_from_fmt(fmt!("{}", ascii)).unwrap(); 216c07e67bdSGary Guo /// assert_eq!(s.as_bytes_with_nul(), "so \"cool\"\0".as_bytes()); 217c07e67bdSGary Guo /// ``` 218c07e67bdSGary Guo fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 219c07e67bdSGary Guo for &c in self.as_bytes() { 220c07e67bdSGary Guo if (0x20..0x7f).contains(&c) { 221c07e67bdSGary Guo // Printable character. 222c07e67bdSGary Guo f.write_char(c as char)?; 223c07e67bdSGary Guo } else { 224c07e67bdSGary Guo write!(f, "\\x{:02x}", c)?; 225c07e67bdSGary Guo } 226c07e67bdSGary Guo } 227c07e67bdSGary Guo Ok(()) 228c07e67bdSGary Guo } 229c07e67bdSGary Guo } 230c07e67bdSGary Guo 231c07e67bdSGary Guo impl fmt::Debug for CStr { 232c07e67bdSGary Guo /// Formats printable ASCII characters with a double quote on either end, escaping the rest. 233c07e67bdSGary Guo /// 234c07e67bdSGary Guo /// ``` 235c07e67bdSGary Guo /// # use kernel::c_str; 236c07e67bdSGary Guo /// # use kernel::str::CStr; 237c07e67bdSGary Guo /// # use kernel::str::CString; 238c07e67bdSGary Guo /// let penguin = c_str!(""); 239c07e67bdSGary Guo /// let s = CString::try_from_fmt(fmt!("{:?}", penguin)).unwrap(); 240c07e67bdSGary Guo /// assert_eq!(s.as_bytes_with_nul(), "\"\\xf0\\x9f\\x90\\xa7\"\0".as_bytes()); 241c07e67bdSGary Guo /// 242c07e67bdSGary Guo /// // Embedded double quotes are escaped. 243c07e67bdSGary Guo /// let ascii = c_str!("so \"cool\""); 244c07e67bdSGary Guo /// let s = CString::try_from_fmt(fmt!("{:?}", ascii)).unwrap(); 245c07e67bdSGary Guo /// assert_eq!(s.as_bytes_with_nul(), "\"so \\\"cool\\\"\"\0".as_bytes()); 246c07e67bdSGary Guo /// ``` 247c07e67bdSGary Guo fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 248c07e67bdSGary Guo f.write_str("\"")?; 249c07e67bdSGary Guo for &c in self.as_bytes() { 250c07e67bdSGary Guo match c { 251c07e67bdSGary Guo // Printable characters. 252c07e67bdSGary Guo b'\"' => f.write_str("\\\"")?, 253c07e67bdSGary Guo 0x20..=0x7e => f.write_char(c as char)?, 254c07e67bdSGary Guo _ => write!(f, "\\x{:02x}", c)?, 255c07e67bdSGary Guo } 256c07e67bdSGary Guo } 257c07e67bdSGary Guo f.write_str("\"") 258c07e67bdSGary Guo } 259c07e67bdSGary Guo } 260c07e67bdSGary Guo 261c07e67bdSGary Guo impl AsRef<BStr> for CStr { 262c07e67bdSGary Guo #[inline] 263c07e67bdSGary Guo fn as_ref(&self) -> &BStr { 264c07e67bdSGary Guo self.as_bytes() 265c07e67bdSGary Guo } 266c07e67bdSGary Guo } 267c07e67bdSGary Guo 268c07e67bdSGary Guo impl Deref for CStr { 269c07e67bdSGary Guo type Target = BStr; 270c07e67bdSGary Guo 271c07e67bdSGary Guo #[inline] 272c07e67bdSGary Guo fn deref(&self) -> &Self::Target { 273c07e67bdSGary Guo self.as_bytes() 274c07e67bdSGary Guo } 275c07e67bdSGary Guo } 276c07e67bdSGary Guo 277c07e67bdSGary Guo impl Index<ops::RangeFrom<usize>> for CStr { 278c07e67bdSGary Guo type Output = CStr; 279c07e67bdSGary Guo 280c07e67bdSGary Guo #[inline] 281c07e67bdSGary Guo fn index(&self, index: ops::RangeFrom<usize>) -> &Self::Output { 282c07e67bdSGary Guo // Delegate bounds checking to slice. 283c07e67bdSGary Guo // Assign to _ to mute clippy's unnecessary operation warning. 284c07e67bdSGary Guo let _ = &self.as_bytes()[index.start..]; 285c07e67bdSGary Guo // SAFETY: We just checked the bounds. 286c07e67bdSGary Guo unsafe { Self::from_bytes_with_nul_unchecked(&self.0[index.start..]) } 287c07e67bdSGary Guo } 288c07e67bdSGary Guo } 289c07e67bdSGary Guo 290c07e67bdSGary Guo impl Index<ops::RangeFull> for CStr { 291c07e67bdSGary Guo type Output = CStr; 292c07e67bdSGary Guo 293c07e67bdSGary Guo #[inline] 294c07e67bdSGary Guo fn index(&self, _index: ops::RangeFull) -> &Self::Output { 295c07e67bdSGary Guo self 296c07e67bdSGary Guo } 297c07e67bdSGary Guo } 298c07e67bdSGary Guo 299c07e67bdSGary Guo mod private { 300c07e67bdSGary Guo use core::ops; 301c07e67bdSGary Guo 302c07e67bdSGary Guo // Marker trait for index types that can be forward to `BStr`. 303c07e67bdSGary Guo pub trait CStrIndex {} 304c07e67bdSGary Guo 305c07e67bdSGary Guo impl CStrIndex for usize {} 306c07e67bdSGary Guo impl CStrIndex for ops::Range<usize> {} 307c07e67bdSGary Guo impl CStrIndex for ops::RangeInclusive<usize> {} 308c07e67bdSGary Guo impl CStrIndex for ops::RangeToInclusive<usize> {} 309c07e67bdSGary Guo } 310c07e67bdSGary Guo 311c07e67bdSGary Guo impl<Idx> Index<Idx> for CStr 312c07e67bdSGary Guo where 313c07e67bdSGary Guo Idx: private::CStrIndex, 314c07e67bdSGary Guo BStr: Index<Idx>, 315c07e67bdSGary Guo { 316c07e67bdSGary Guo type Output = <BStr as Index<Idx>>::Output; 317c07e67bdSGary Guo 318c07e67bdSGary Guo #[inline] 319c07e67bdSGary Guo fn index(&self, index: Idx) -> &Self::Output { 320c07e67bdSGary Guo &self.as_bytes()[index] 321c07e67bdSGary Guo } 322c07e67bdSGary Guo } 323c07e67bdSGary Guo 324*b18cb00eSGary Guo /// Creates a new [`CStr`] from a string literal. 325*b18cb00eSGary Guo /// 326*b18cb00eSGary Guo /// The string literal should not contain any `NUL` bytes. 327*b18cb00eSGary Guo /// 328*b18cb00eSGary Guo /// # Examples 329*b18cb00eSGary Guo /// 330*b18cb00eSGary Guo /// ``` 331*b18cb00eSGary Guo /// # use kernel::c_str; 332*b18cb00eSGary Guo /// # use kernel::str::CStr; 333*b18cb00eSGary Guo /// const MY_CSTR: &CStr = c_str!("My awesome CStr!"); 334*b18cb00eSGary Guo /// ``` 335*b18cb00eSGary Guo #[macro_export] 336*b18cb00eSGary Guo macro_rules! c_str { 337*b18cb00eSGary Guo ($str:expr) => {{ 338*b18cb00eSGary Guo const S: &str = concat!($str, "\0"); 339*b18cb00eSGary Guo const C: &$crate::str::CStr = match $crate::str::CStr::from_bytes_with_nul(S.as_bytes()) { 340*b18cb00eSGary Guo Ok(v) => v, 341*b18cb00eSGary Guo Err(_) => panic!("string contains interior NUL"), 342*b18cb00eSGary Guo }; 343*b18cb00eSGary Guo C 344*b18cb00eSGary Guo }}; 345*b18cb00eSGary Guo } 346*b18cb00eSGary Guo 347985f1f09SMilan Landaverde #[cfg(test)] 348985f1f09SMilan Landaverde mod tests { 349985f1f09SMilan Landaverde use super::*; 350985f1f09SMilan Landaverde 351985f1f09SMilan Landaverde #[test] 352985f1f09SMilan Landaverde fn test_cstr_to_str() { 353985f1f09SMilan Landaverde let good_bytes = b"\xf0\x9f\xa6\x80\0"; 354985f1f09SMilan Landaverde let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap(); 355985f1f09SMilan Landaverde let checked_str = checked_cstr.to_str().unwrap(); 356985f1f09SMilan Landaverde assert_eq!(checked_str, ""); 357985f1f09SMilan Landaverde } 358985f1f09SMilan Landaverde 359985f1f09SMilan Landaverde #[test] 360985f1f09SMilan Landaverde #[should_panic] 361985f1f09SMilan Landaverde fn test_cstr_to_str_panic() { 362985f1f09SMilan Landaverde let bad_bytes = b"\xc3\x28\0"; 363985f1f09SMilan Landaverde let checked_cstr = CStr::from_bytes_with_nul(bad_bytes).unwrap(); 364985f1f09SMilan Landaverde checked_cstr.to_str().unwrap(); 365985f1f09SMilan Landaverde } 366985f1f09SMilan Landaverde 367985f1f09SMilan Landaverde #[test] 368985f1f09SMilan Landaverde fn test_cstr_as_str_unchecked() { 369985f1f09SMilan Landaverde let good_bytes = b"\xf0\x9f\x90\xA7\0"; 370985f1f09SMilan Landaverde let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap(); 371985f1f09SMilan Landaverde let unchecked_str = unsafe { checked_cstr.as_str_unchecked() }; 372985f1f09SMilan Landaverde assert_eq!(unchecked_str, ""); 373985f1f09SMilan Landaverde } 374985f1f09SMilan Landaverde } 375985f1f09SMilan Landaverde 376247b365dSWedson Almeida Filho /// Allows formatting of [`fmt::Arguments`] into a raw buffer. 377247b365dSWedson Almeida Filho /// 378247b365dSWedson Almeida Filho /// It does not fail if callers write past the end of the buffer so that they can calculate the 379247b365dSWedson Almeida Filho /// size required to fit everything. 380247b365dSWedson Almeida Filho /// 381247b365dSWedson Almeida Filho /// # Invariants 382247b365dSWedson Almeida Filho /// 383247b365dSWedson Almeida Filho /// The memory region between `pos` (inclusive) and `end` (exclusive) is valid for writes if `pos` 384247b365dSWedson Almeida Filho /// is less than `end`. 385247b365dSWedson Almeida Filho pub(crate) struct RawFormatter { 386247b365dSWedson Almeida Filho // Use `usize` to use `saturating_*` functions. 387247b365dSWedson Almeida Filho #[allow(dead_code)] 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 { 394247b365dSWedson Almeida Filho /// Creates a new instance of [`RawFormatter`] with the given buffer pointers. 395247b365dSWedson Almeida Filho /// 396247b365dSWedson Almeida Filho /// # Safety 397247b365dSWedson Almeida Filho /// 398247b365dSWedson Almeida Filho /// If `pos` is less than `end`, then the region between `pos` (inclusive) and `end` 399247b365dSWedson Almeida Filho /// (exclusive) must be valid for writes for the lifetime of the returned [`RawFormatter`]. 400247b365dSWedson Almeida Filho pub(crate) unsafe fn from_ptrs(pos: *mut u8, end: *mut u8) -> Self { 401247b365dSWedson Almeida Filho // INVARIANT: The safety requierments guarantee the type invariants. 402247b365dSWedson Almeida Filho Self { 403247b365dSWedson Almeida Filho beg: pos as _, 404247b365dSWedson Almeida Filho pos: pos as _, 405247b365dSWedson Almeida Filho end: end as _, 406247b365dSWedson Almeida Filho } 407247b365dSWedson Almeida Filho } 408247b365dSWedson Almeida Filho 409247b365dSWedson Almeida Filho /// Returns the current insert position. 410247b365dSWedson Almeida Filho /// 411247b365dSWedson Almeida Filho /// N.B. It may point to invalid memory. 412247b365dSWedson Almeida Filho pub(crate) fn pos(&self) -> *mut u8 { 413247b365dSWedson Almeida Filho self.pos as _ 414247b365dSWedson Almeida Filho } 415247b365dSWedson Almeida Filho } 416247b365dSWedson Almeida Filho 417247b365dSWedson Almeida Filho impl fmt::Write for RawFormatter { 418247b365dSWedson Almeida Filho fn write_str(&mut self, s: &str) -> fmt::Result { 419247b365dSWedson Almeida Filho // `pos` value after writing `len` bytes. This does not have to be bounded by `end`, but we 420247b365dSWedson Almeida Filho // don't want it to wrap around to 0. 421247b365dSWedson Almeida Filho let pos_new = self.pos.saturating_add(s.len()); 422247b365dSWedson Almeida Filho 423247b365dSWedson Almeida Filho // Amount that we can copy. `saturating_sub` ensures we get 0 if `pos` goes past `end`. 424247b365dSWedson Almeida Filho let len_to_copy = core::cmp::min(pos_new, self.end).saturating_sub(self.pos); 425247b365dSWedson Almeida Filho 426247b365dSWedson Almeida Filho if len_to_copy > 0 { 427247b365dSWedson Almeida Filho // SAFETY: If `len_to_copy` is non-zero, then we know `pos` has not gone past `end` 428247b365dSWedson Almeida Filho // yet, so it is valid for write per the type invariants. 429247b365dSWedson Almeida Filho unsafe { 430247b365dSWedson Almeida Filho core::ptr::copy_nonoverlapping( 431247b365dSWedson Almeida Filho s.as_bytes().as_ptr(), 432247b365dSWedson Almeida Filho self.pos as *mut u8, 433247b365dSWedson Almeida Filho len_to_copy, 434247b365dSWedson Almeida Filho ) 435247b365dSWedson Almeida Filho }; 436247b365dSWedson Almeida Filho } 437247b365dSWedson Almeida Filho 438247b365dSWedson Almeida Filho self.pos = pos_new; 439247b365dSWedson Almeida Filho Ok(()) 440247b365dSWedson Almeida Filho } 441247b365dSWedson Almeida Filho } 442