Skip to content

Commit 483c5fa

Browse files
Andreas Hindborgkawasaki
authored andcommitted
rust: str: introduce NullTerminatedFormatter
Add `NullTerminatedFormatter`, a formatter that writes a null terminated string to an array or slice buffer. Because this type needs to manage the trailing null marker, the existing formatters cannot be used to implement this type. Signed-off-by: Andreas Hindborg <[email protected]>
1 parent e3b9ab6 commit 483c5fa

1 file changed

Lines changed: 50 additions & 0 deletions

File tree

rust/kernel/str.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,56 @@ impl fmt::Write for Formatter<'_> {
838838
}
839839
}
840840

841+
/// A mutable reference to a byte buffer where a string can be written into.
842+
///
843+
/// The buffer will be automatically null terminated after the last written character.
844+
///
845+
/// # Invariants
846+
///
847+
/// `buffer` is always null terminated.
848+
pub(crate) struct NullTerminatedFormatter<'a> {
849+
buffer: &'a mut [u8],
850+
}
851+
852+
impl<'a> NullTerminatedFormatter<'a> {
853+
/// Create a new [`Self`] instance.
854+
pub(crate) fn new(buffer: &'a mut [u8]) -> Option<NullTerminatedFormatter<'a>> {
855+
*(buffer.first_mut()?) = 0;
856+
857+
// INVARIANT: We null terminated the buffer above.
858+
Some(Self { buffer })
859+
}
860+
861+
#[expect(dead_code)]
862+
pub(crate) fn from_array<const N: usize>(
863+
buffer: &'a mut [crate::ffi::c_char; N],
864+
) -> Option<NullTerminatedFormatter<'a>> {
865+
Self::new(buffer)
866+
}
867+
}
868+
869+
impl Write for NullTerminatedFormatter<'_> {
870+
fn write_str(&mut self, s: &str) -> fmt::Result {
871+
let bytes = s.as_bytes();
872+
let len = bytes.len();
873+
874+
// We want space for a null terminator. Buffer length is always at least 1, so no overflow.
875+
if len > self.buffer.len() - 1 {
876+
return Err(fmt::Error);
877+
}
878+
879+
let buffer = core::mem::take(&mut self.buffer);
880+
// We break the null termination invariant for a short while.
881+
buffer[..len].copy_from_slice(bytes);
882+
self.buffer = &mut buffer[len..];
883+
884+
// INVARIANT: We null terminate the buffer.
885+
self.buffer[0] = 0;
886+
887+
Ok(())
888+
}
889+
}
890+
841891
/// An owned string that is guaranteed to have exactly one `NUL` byte, which is at the end.
842892
///
843893
/// Used for interoperability with kernel APIs that take C strings.

0 commit comments

Comments
 (0)