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