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