//! The `ByteStr` type and trait implementations. mod traits; #[unstable(feature = "bstr_internals", issue = "none")] pub use traits::{impl_partial_eq, impl_partial_eq_n, impl_partial_eq_ord}; use crate::borrow::{Borrow, BorrowMut}; use crate::fmt; use crate::ops::{Deref, DerefMut, DerefPure}; /// A wrapper for `&[u8]` representing a human-readable string that's conventionally, but not /// always, UTF-8. /// /// Unlike `&str`, this type permits non-UTF-8 contents, making it suitable for user input, /// non-native filenames (as `Path` only supports native filenames), and other applications that /// need to round-trip whatever data the user provides. /// /// For an owned, growable byte string buffer, use /// [`ByteString`](../../std/bstr/struct.ByteString.html). /// /// `ByteStr` implements `Deref` to `[u8]`, so all methods available on `[u8]` are available on /// `ByteStr`. /// /// # Representation /// /// A `&ByteStr` has the same representation as a `&str`. That is, a `&ByteStr` is a wide pointer /// which includes a pointer to some bytes and a length. /// /// # Trait implementations /// /// The `ByteStr` type has a number of trait implementations, and in particular, defines equality /// and comparisons between `&ByteStr`, `&str`, and `&[u8]`, for convenience. /// /// The `Debug` implementation for `ByteStr` shows its bytes as a normal string, with invalid UTF-8 /// presented as hex escape sequences. /// /// The `Display` implementation behaves as if the `ByteStr` were first lossily converted to a /// `str`, with invalid UTF-8 presented as the Unicode replacement character: � /// #[unstable(feature = "bstr", issue = "134915")] #[repr(transparent)] #[doc(alias = "BStr")] pub struct ByteStr(pub [u8]); impl ByteStr { /// Creates a `ByteStr` slice from anything that can be converted to a byte slice. /// /// This is a zero-cost conversion. /// /// # Example /// /// You can create a `ByteStr` from a byte array, a byte slice or a string slice: /// /// ``` /// # #![feature(bstr)] /// # use std::bstr::ByteStr; /// let a = ByteStr::new(b"abc"); /// let b = ByteStr::new(&b"abc"[..]); /// let c = ByteStr::new("abc"); /// /// assert_eq!(a, b); /// assert_eq!(a, c); /// ``` #[inline] #[unstable(feature = "bstr", issue = "134915")] pub fn new>(bytes: &B) -> &Self { ByteStr::from_bytes(bytes.as_ref()) } #[doc(hidden)] #[unstable(feature = "bstr_internals", issue = "none")] #[inline] pub fn from_bytes(slice: &[u8]) -> &Self { // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`, so we can turn a reference to // the wrapped type into a reference to the wrapper type. unsafe { &*(slice as *const [u8] as *const Self) } } #[doc(hidden)] #[unstable(feature = "bstr_internals", issue = "none")] #[inline] pub fn from_bytes_mut(slice: &mut [u8]) -> &mut Self { // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`, so we can turn a reference to // the wrapped type into a reference to the wrapper type. unsafe { &mut *(slice as *mut [u8] as *mut Self) } } #[doc(hidden)] #[unstable(feature = "bstr_internals", issue = "none")] #[inline] pub fn as_bytes(&self) -> &[u8] { &self.0 } #[doc(hidden)] #[unstable(feature = "bstr_internals", issue = "none")] #[inline] pub fn as_bytes_mut(&mut self) -> &mut [u8] { &mut self.0 } } #[unstable(feature = "bstr", issue = "134915")] impl Deref for ByteStr { type Target = [u8]; #[inline] fn deref(&self) -> &[u8] { &self.0 } } #[unstable(feature = "bstr", issue = "134915")] impl DerefMut for ByteStr { #[inline] fn deref_mut(&mut self) -> &mut [u8] { &mut self.0 } } #[unstable(feature = "deref_pure_trait", issue = "87121")] unsafe impl DerefPure for ByteStr {} #[unstable(feature = "bstr", issue = "134915")] impl fmt::Debug for ByteStr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "\"")?; for chunk in self.utf8_chunks() { for c in chunk.valid().chars() { match c { '\0' => write!(f, "\\0")?, '\x01'..='\x7f' => write!(f, "{}", (c as u8).escape_ascii())?, _ => write!(f, "{}", c.escape_debug())?, } } write!(f, "{}", chunk.invalid().escape_ascii())?; } write!(f, "\"")?; Ok(()) } } #[unstable(feature = "bstr", issue = "134915")] impl fmt::Display for ByteStr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt_nopad(this: &ByteStr, f: &mut fmt::Formatter<'_>) -> fmt::Result { for chunk in this.utf8_chunks() { f.write_str(chunk.valid())?; if !chunk.invalid().is_empty() { f.write_str("\u{FFFD}")?; } } Ok(()) } let Some(align) = f.align() else { return fmt_nopad(self, f); }; let nchars: usize = self .utf8_chunks() .map(|chunk| { chunk.valid().chars().count() + if chunk.invalid().is_empty() { 0 } else { 1 } }) .sum(); let padding = f.width().unwrap_or(0).saturating_sub(nchars); let fill = f.fill(); let (lpad, rpad) = match align { fmt::Alignment::Left => (0, padding), fmt::Alignment::Right => (padding, 0), fmt::Alignment::Center => { let half = padding / 2; (half, half + padding % 2) } }; for _ in 0..lpad { write!(f, "{fill}")?; } fmt_nopad(self, f)?; for _ in 0..rpad { write!(f, "{fill}")?; } Ok(()) } } #[unstable(feature = "bstr", issue = "134915")] impl AsRef<[u8]> for ByteStr { #[inline] fn as_ref(&self) -> &[u8] { &self.0 } } #[unstable(feature = "bstr", issue = "134915")] impl AsRef for ByteStr { #[inline] fn as_ref(&self) -> &ByteStr { self } } // `impl AsRef for [u8]` omitted to avoid widespread inference failures #[unstable(feature = "bstr", issue = "134915")] impl AsRef for str { #[inline] fn as_ref(&self) -> &ByteStr { ByteStr::new(self) } } #[unstable(feature = "bstr", issue = "134915")] impl AsMut<[u8]> for ByteStr { #[inline] fn as_mut(&mut self) -> &mut [u8] { &mut self.0 } } // `impl AsMut for [u8]` omitted to avoid widespread inference failures // `impl Borrow for [u8]` omitted to avoid widespread inference failures // `impl Borrow for str` omitted to avoid widespread inference failures #[unstable(feature = "bstr", issue = "134915")] impl Borrow<[u8]> for ByteStr { #[inline] fn borrow(&self) -> &[u8] { &self.0 } } // `impl BorrowMut for [u8]` omitted to avoid widespread inference failures #[unstable(feature = "bstr", issue = "134915")] impl BorrowMut<[u8]> for ByteStr { #[inline] fn borrow_mut(&mut self) -> &mut [u8] { &mut self.0 } } #[unstable(feature = "bstr", issue = "134915")] impl<'a> Default for &'a ByteStr { fn default() -> Self { ByteStr::from_bytes(b"") } } #[unstable(feature = "bstr", issue = "134915")] impl<'a> Default for &'a mut ByteStr { fn default() -> Self { ByteStr::from_bytes_mut(&mut []) } } // Omitted due to inference failures // // #[unstable(feature = "bstr", issue = "134915")] // impl<'a, const N: usize> From<&'a [u8; N]> for &'a ByteStr { // #[inline] // fn from(s: &'a [u8; N]) -> Self { // ByteStr::from_bytes(s) // } // } // // #[unstable(feature = "bstr", issue = "134915")] // impl<'a> From<&'a [u8]> for &'a ByteStr { // #[inline] // fn from(s: &'a [u8]) -> Self { // ByteStr::from_bytes(s) // } // } // Omitted due to slice-from-array-issue-113238: // // #[unstable(feature = "bstr", issue = "134915")] // impl<'a> From<&'a ByteStr> for &'a [u8] { // #[inline] // fn from(s: &'a ByteStr) -> Self { // &s.0 // } // } // // #[unstable(feature = "bstr", issue = "134915")] // impl<'a> From<&'a mut ByteStr> for &'a mut [u8] { // #[inline] // fn from(s: &'a mut ByteStr) -> Self { // &mut s.0 // } // } // Omitted due to inference failures // // #[unstable(feature = "bstr", issue = "134915")] // impl<'a> From<&'a str> for &'a ByteStr { // #[inline] // fn from(s: &'a str) -> Self { // ByteStr::from_bytes(s.as_bytes()) // } // } #[unstable(feature = "bstr", issue = "134915")] impl<'a> TryFrom<&'a ByteStr> for &'a str { type Error = crate::str::Utf8Error; #[inline] fn try_from(s: &'a ByteStr) -> Result { crate::str::from_utf8(&s.0) } } #[unstable(feature = "bstr", issue = "134915")] impl<'a> TryFrom<&'a mut ByteStr> for &'a mut str { type Error = crate::str::Utf8Error; #[inline] fn try_from(s: &'a mut ByteStr) -> Result { crate::str::from_utf8_mut(&mut s.0) } }