linux/rust/kernel/str.rs
Gary Guo 650ec51561 rust: str: add b_str! macro
Add the `b_str!` macro, which creates a new `BStr` from
a string literal.

It is usable in const contexts, for instance:

    const X: &BStr = b_str!("Example");

Signed-off-by: Gary Guo <gary@garyguo.net>
[Reworded, adapted for upstream and applied latest changes]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2022-12-04 01:59:15 +01:00

99 lines
2.9 KiB
Rust

// SPDX-License-Identifier: GPL-2.0
//! String representations.
use core::fmt;
/// Byte string without UTF-8 validity guarantee.
///
/// `BStr` is simply an alias to `[u8]`, but has a more evident semantical meaning.
pub type BStr = [u8];
/// Creates a new [`BStr`] from a string literal.
///
/// `b_str!` converts the supplied string literal to byte string, so non-ASCII
/// characters can be included.
///
/// # Examples
///
/// ```
/// # use kernel::b_str;
/// # use kernel::str::BStr;
/// const MY_BSTR: &BStr = b_str!("My awesome BStr!");
/// ```
#[macro_export]
macro_rules! b_str {
($str:literal) => {{
const S: &'static str = $str;
const C: &'static $crate::str::BStr = S.as_bytes();
C
}};
}
/// 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(())
}
}