1 // SPDX-License-Identifier: GPL-2.0 2 3 //! String representations. 4 5 use core::fmt; 6 7 /// Byte string without UTF-8 validity guarantee. 8 /// 9 /// `BStr` is simply an alias to `[u8]`, but has a more evident semantical meaning. 10 pub type BStr = [u8]; 11 12 /// Allows formatting of [`fmt::Arguments`] into a raw buffer. 13 /// 14 /// It does not fail if callers write past the end of the buffer so that they can calculate the 15 /// size required to fit everything. 16 /// 17 /// # Invariants 18 /// 19 /// The memory region between `pos` (inclusive) and `end` (exclusive) is valid for writes if `pos` 20 /// is less than `end`. 21 pub(crate) struct RawFormatter { 22 // Use `usize` to use `saturating_*` functions. 23 #[allow(dead_code)] 24 beg: usize, 25 pos: usize, 26 end: usize, 27 } 28 29 impl RawFormatter { 30 /// Creates a new instance of [`RawFormatter`] with the given buffer pointers. 31 /// 32 /// # Safety 33 /// 34 /// If `pos` is less than `end`, then the region between `pos` (inclusive) and `end` 35 /// (exclusive) must be valid for writes for the lifetime of the returned [`RawFormatter`]. 36 pub(crate) unsafe fn from_ptrs(pos: *mut u8, end: *mut u8) -> Self { 37 // INVARIANT: The safety requierments guarantee the type invariants. 38 Self { 39 beg: pos as _, 40 pos: pos as _, 41 end: end as _, 42 } 43 } 44 45 /// Returns the current insert position. 46 /// 47 /// N.B. It may point to invalid memory. 48 pub(crate) fn pos(&self) -> *mut u8 { 49 self.pos as _ 50 } 51 } 52 53 impl fmt::Write for RawFormatter { 54 fn write_str(&mut self, s: &str) -> fmt::Result { 55 // `pos` value after writing `len` bytes. This does not have to be bounded by `end`, but we 56 // don't want it to wrap around to 0. 57 let pos_new = self.pos.saturating_add(s.len()); 58 59 // Amount that we can copy. `saturating_sub` ensures we get 0 if `pos` goes past `end`. 60 let len_to_copy = core::cmp::min(pos_new, self.end).saturating_sub(self.pos); 61 62 if len_to_copy > 0 { 63 // SAFETY: If `len_to_copy` is non-zero, then we know `pos` has not gone past `end` 64 // yet, so it is valid for write per the type invariants. 65 unsafe { 66 core::ptr::copy_nonoverlapping( 67 s.as_bytes().as_ptr(), 68 self.pos as *mut u8, 69 len_to_copy, 70 ) 71 }; 72 } 73 74 self.pos = pos_new; 75 Ok(()) 76 } 77 } 78