// SPDX-License-Identifier: GPL-2.0
//! String representations.
use crate::alloc::{flags::*, AllocError, KVec};
use core::fmt::{self, Write};
use core::ops::{self, Deref, DerefMut, Index};
use crate::error::{code::*, Error};
/// Byte string without UTF-8 validity guarantee.
#[repr(transparent)]
pub struct BStr([u8]);
impl BStr {
/// Returns the length of this string.
#[inline]
pub const fn len(&self) -> usize {
self.0.len()
}
/// Returns `true` if the string is empty.
#[inline]
pub const fn is_empty(&self) -> bool {
self.len() == 0
}
/// Creates a [`BStr`] from a `[u8]`.
#[inline]
pub const fn from_bytes(bytes: &[u8]) -> &Self {
// SAFETY: `BStr` is transparent to `[u8]`.
unsafe { &*(bytes as *const [u8] as *const BStr) }
}
/// Strip a prefix from `self`. Delegates to [`slice::strip_prefix`].
///
/// # Examples
///
/// ```
/// # use kernel::b_str;
/// assert_eq!(Some(b_str!("bar")), b_str!("foobar").strip_prefix(b_str!("foo")));
/// assert_eq!(None, b_str!("foobar").strip_prefix(b_str!("bar")));
/// assert_eq!(Some(b_str!("foobar")), b_str!("foobar").strip_prefix(b_str!("")));
/// assert_eq!(Some(b_str!("")), b_str!("foobar").strip_prefix(b_str!("foobar")));
/// ```
pub fn strip_prefix(&self, pattern: impl AsRef<Self>) -> Option<&BStr> {
self.deref()
.strip_prefix(pattern.as_ref().deref())
.map(Self::from_bytes)
}
}
impl fmt::Display for BStr {
/// Formats printable ASCII characters, escaping the rest.
///
/// ```
/// # use kernel::{fmt, b_str, str::{BStr, CString}};
/// let ascii = b_str!("Hello, BStr!");
/// let s = CString::try_from_fmt(fmt!("{}", ascii))?;
/// assert_eq!(s.as_bytes(), "Hello, BStr!".as_bytes());
///
/// let non_ascii = b_str!("🦀");
/// let s = CString::try_from_fmt(fmt!("{}", non_ascii))?;
/// assert_eq!(s.as_bytes(), "\\xf0\\x9f\\xa6\\x80".as_bytes());
/// # Ok::<(), kernel::error::Error>(())
/// ```
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for &b in &self.0 {
match b {
// Common escape codes.
b'\t' => f.write_str("\\t")?,
b'\n' => f.write_str("\\n")?,
b'\r' => f.write_str("\\r")?,
// Printable characters.
0x20..=0x7e => f.write_char(b as char)?,
_ => write!(f, "\\x{b:02x}")?,
}
}
Ok(())
}
}
impl fmt::Debug for BStr {
/// Formats printable ASCII characters with a double quote on either end,
/// escaping the rest.
///
/// ```
/// # use kernel::{fmt, b_str, str::{BStr, CString}};
/// // Embedded double quotes are escaped.
/// let ascii = b_str!("Hello, \"BStr\"!");
/// let s = CString::try_from_fmt(fmt!("{:?}", ascii))?;
/// assert_eq!(s.as_bytes(), "\"Hello, \\\"BStr\\\"!\"".as_bytes());
///
/// let non_ascii = b_str!("😺");
/// let s = CString::try_from_fmt(fmt!("{:?}", non_ascii))?;
/// assert_eq!(s.as_bytes(), "\"\\xf0\\x9f\\x98\\xba\"".as_bytes());
/// # Ok::<(), kernel::error::Error>(())
/// ```
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_char('"')?;
for &b in &self.0 {
match b {
// Common escape codes.
b'\t' => f.write_str("\\t")?,
b'\n' => f.write_str("\\n")?,
b'\r' => f.write_str("\\r")?,
// String escape characters.
b'\"' => f.write_str("\\\"")?,
b'\\' => f.write_str("\\\\")?,
// Printable characters.
0x20..=0x7e => f.write_char(b as char)?,
_ => write!(f, "\\x{b:02x}")?,
}
}
f.write_char('"')
}
}
impl Deref for BStr {
type Target = [u8];
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl PartialEq for BStr {
fn eq(&self, other: &Self) -> bool {
self.deref().eq(other.deref())
}
}
impl<Idx> Index<Idx> for BStr
where
[u8]: Index<Idx, Output = [u8]>,
{
type Output = Self;
fn index(&self, index: Idx) -> &Self::Output {
BStr::