forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
72 lines
2.2 KiB
72 lines
2.2 KiB
// 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 requierments 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(()) |
|
} |
|
}
|
|
|