123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172 |
- // SPDX-License-Identifier: GPL-2.0
- //! String representations.
- use core::fmt;
- /// Allows formatting of [`fmt::Arguments`] into a raw buffer.
- ///
- /// It does not fail if callers write past the end of the buffer so that they can calculate the
- /// size required to fit everything.
- ///
- /// # Invariants
- ///
- /// The memory region between `pos` (inclusive) and `end` (exclusive) is valid for writes if `pos`
- /// is less than `end`.
- pub(crate) struct RawFormatter {
- // Use `usize` to use `saturating_*` functions.
- #[allow(dead_code)]
- beg: usize,
- pos: usize,
- end: usize,
- }
- impl RawFormatter {
- /// Creates a new instance of [`RawFormatter`] with the given buffer pointers.
- ///
- /// # Safety
- ///
- /// If `pos` is less than `end`, then the region between `pos` (inclusive) and `end`
- /// (exclusive) must be valid for writes for the lifetime of the returned [`RawFormatter`].
- pub(crate) unsafe fn from_ptrs(pos: *mut u8, end: *mut u8) -> Self {
- // INVARIANT: The safety requirements guarantee the type invariants.
- Self {
- beg: pos as _,
- pos: pos as _,
- end: end as _,
- }
- }
- /// Returns the current insert position.
- ///
- /// N.B. It may point to invalid memory.
- pub(crate) fn pos(&self) -> *mut u8 {
- self.pos as _
- }
- }
- impl fmt::Write for RawFormatter {
- fn write_str(&mut self, s: &str) -> fmt::Result {
- // `pos` value after writing `len` bytes. This does not have to be bounded by `end`, but we
- // don't want it to wrap around to 0.
- let pos_new = self.pos.saturating_add(s.len());
- // Amount that we can copy. `saturating_sub` ensures we get 0 if `pos` goes past `end`.
- let len_to_copy = core::cmp::min(pos_new, self.end).saturating_sub(self.pos);
- if len_to_copy > 0 {
- // SAFETY: If `len_to_copy` is non-zero, then we know `pos` has not gone past `end`
- // yet, so it is valid for write per the type invariants.
- unsafe {
- core::ptr::copy_nonoverlapping(
- s.as_bytes().as_ptr(),
- self.pos as *mut u8,
- len_to_copy,
- )
- };
- }
- self.pos = pos_new;
- Ok(())
- }
- }
|