Skip to content

Commit 1e7d197

Browse files
Andreas Hindborgkawasaki
authored andcommitted
rust: str: introduce NullBorrowFormatter
Add `NullBorrowFormatter`, 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 8315589 commit 1e7d197

1 file changed

Lines changed: 59 additions & 0 deletions

File tree

rust/kernel/str.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -860,6 +860,65 @@ impl DerefMut for BorrowFormatter<'_> {
860860
}
861861
}
862862

863+
/// A mutable reference to a byte buffer where a string can be written into.
864+
///
865+
/// The buffer will be automatically null terminated after the last written character.
866+
///
867+
/// # Invariants
868+
///
869+
/// `buffer` is always null terminated.
870+
pub(crate) struct NullBorrowFormatter<'a> {
871+
buffer: &'a mut [u8],
872+
pos: usize,
873+
}
874+
875+
impl<'a> NullBorrowFormatter<'a> {
876+
/// Create a new [`Self`] instance.
877+
pub(crate) fn new(buffer: &'a mut [u8]) -> Result<NullBorrowFormatter<'a>> {
878+
*(buffer.first_mut().ok_or(EINVAL)?) = 0;
879+
880+
// INVARIANT: We null terminated the buffer above.
881+
Ok(Self { buffer, pos: 0 })
882+
}
883+
884+
#[expect(dead_code)]
885+
pub(crate) fn from_array<const N: usize>(
886+
a: &'a mut [crate::ffi::c_char; N],
887+
) -> Result<NullBorrowFormatter<'a>> {
888+
Self::new(
889+
// SAFETY: the buffer of `a` is valid for read and write as `u8` for
890+
// at least `N` bytes.
891+
unsafe { core::slice::from_raw_parts_mut(a.as_mut_ptr().cast::<u8>(), N) },
892+
)
893+
}
894+
895+
/// Return the position of the write pointer in the underlying buffer.
896+
#[expect(dead_code)]
897+
pub(crate) fn pos(&self) -> usize {
898+
self.pos
899+
}
900+
}
901+
902+
impl Write for NullBorrowFormatter<'_> {
903+
fn write_str(&mut self, s: &str) -> fmt::Result {
904+
let bytes = s.as_bytes();
905+
let len = bytes.len();
906+
907+
// We want space for a null terminator
908+
if self.pos + len > self.buffer.len() - 1 {
909+
return Err(fmt::Error);
910+
}
911+
912+
self.buffer[self.pos..self.pos + len].copy_from_slice(bytes);
913+
self.pos += len;
914+
915+
// INVARIANT: The buffer is null terminated.
916+
self.buffer[self.pos] = 0;
917+
918+
Ok(())
919+
}
920+
}
921+
863922
/// An owned string that is guaranteed to have exactly one `NUL` byte, which is at the end.
864923
///
865924
/// Used for interoperability with kernel APIs that take C strings.

0 commit comments

Comments
 (0)