xref: /openbmc/linux/rust/kernel/str.rs (revision 650ec51561fd201bcf47ce9b1d9b6fedd4bb60a6)
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 /// Creates a new [`BStr`] from a string literal.
13 ///
14 /// `b_str!` converts the supplied string literal to byte string, so non-ASCII
15 /// characters can be included.
16 ///
17 /// # Examples
18 ///
19 /// ```
20 /// # use kernel::b_str;
21 /// # use kernel::str::BStr;
22 /// const MY_BSTR: &BStr = b_str!("My awesome BStr!");
23 /// ```
24 #[macro_export]
25 macro_rules! b_str {
26     ($str:literal) => {{
27         const S: &'static str = $str;
28         const C: &'static $crate::str::BStr = S.as_bytes();
29         C
30     }};
31 }
32 
33 /// Allows formatting of [`fmt::Arguments`] into a raw buffer.
34 ///
35 /// It does not fail if callers write past the end of the buffer so that they can calculate the
36 /// size required to fit everything.
37 ///
38 /// # Invariants
39 ///
40 /// The memory region between `pos` (inclusive) and `end` (exclusive) is valid for writes if `pos`
41 /// is less than `end`.
42 pub(crate) struct RawFormatter {
43     // Use `usize` to use `saturating_*` functions.
44     #[allow(dead_code)]
45     beg: usize,
46     pos: usize,
47     end: usize,
48 }
49 
50 impl RawFormatter {
51     /// Creates a new instance of [`RawFormatter`] with the given buffer pointers.
52     ///
53     /// # Safety
54     ///
55     /// If `pos` is less than `end`, then the region between `pos` (inclusive) and `end`
56     /// (exclusive) must be valid for writes for the lifetime of the returned [`RawFormatter`].
57     pub(crate) unsafe fn from_ptrs(pos: *mut u8, end: *mut u8) -> Self {
58         // INVARIANT: The safety requierments guarantee the type invariants.
59         Self {
60             beg: pos as _,
61             pos: pos as _,
62             end: end as _,
63         }
64     }
65 
66     /// Returns the current insert position.
67     ///
68     /// N.B. It may point to invalid memory.
69     pub(crate) fn pos(&self) -> *mut u8 {
70         self.pos as _
71     }
72 }
73 
74 impl fmt::Write for RawFormatter {
75     fn write_str(&mut self, s: &str) -> fmt::Result {
76         // `pos` value after writing `len` bytes. This does not have to be bounded by `end`, but we
77         // don't want it to wrap around to 0.
78         let pos_new = self.pos.saturating_add(s.len());
79 
80         // Amount that we can copy. `saturating_sub` ensures we get 0 if `pos` goes past `end`.
81         let len_to_copy = core::cmp::min(pos_new, self.end).saturating_sub(self.pos);
82 
83         if len_to_copy > 0 {
84             // SAFETY: If `len_to_copy` is non-zero, then we know `pos` has not gone past `end`
85             // yet, so it is valid for write per the type invariants.
86             unsafe {
87                 core::ptr::copy_nonoverlapping(
88                     s.as_bytes().as_ptr(),
89                     self.pos as *mut u8,
90                     len_to_copy,
91                 )
92             };
93         }
94 
95         self.pos = pos_new;
96         Ok(())
97     }
98 }
99