core/bstr/
mod.rs

1//! The `ByteStr` type and trait implementations.
2
3mod traits;
4
5#[unstable(feature = "bstr_internals", issue = "none")]
6pub use traits::{impl_partial_eq, impl_partial_eq_n, impl_partial_eq_ord};
7
8use crate::borrow::{Borrow, BorrowMut};
9use crate::fmt;
10use crate::ops::{Deref, DerefMut, DerefPure};
11
12/// A wrapper for `&[u8]` representing a human-readable string that's conventionally, but not
13/// always, UTF-8.
14///
15/// Unlike `&str`, this type permits non-UTF-8 contents, making it suitable for user input,
16/// non-native filenames (as `Path` only supports native filenames), and other applications that
17/// need to round-trip whatever data the user provides.
18///
19/// For an owned, growable byte string buffer, use
20/// [`ByteString`](../../std/bstr/struct.ByteString.html).
21///
22/// `ByteStr` implements `Deref` to `[u8]`, so all methods available on `[u8]` are available on
23/// `ByteStr`.
24///
25/// # Representation
26///
27/// A `&ByteStr` has the same representation as a `&str`. That is, a `&ByteStr` is a wide pointer
28/// which includes a pointer to some bytes and a length.
29///
30/// # Trait implementations
31///
32/// The `ByteStr` type has a number of trait implementations, and in particular, defines equality
33/// and comparisons between `&ByteStr`, `&str`, and `&[u8]`, for convenience.
34///
35/// The `Debug` implementation for `ByteStr` shows its bytes as a normal string, with invalid UTF-8
36/// presented as hex escape sequences.
37///
38/// The `Display` implementation behaves as if the `ByteStr` were first lossily converted to a
39/// `str`, with invalid UTF-8 presented as the Unicode replacement character (�).
40#[unstable(feature = "bstr", issue = "134915")]
41#[repr(transparent)]
42#[doc(alias = "BStr")]
43pub struct ByteStr(pub [u8]);
44
45impl ByteStr {
46    /// Creates a `ByteStr` slice from anything that can be converted to a byte slice.
47    ///
48    /// This is a zero-cost conversion.
49    ///
50    /// # Example
51    ///
52    /// You can create a `ByteStr` from a byte array, a byte slice or a string slice:
53    ///
54    /// ```
55    /// # #![feature(bstr)]
56    /// # use std::bstr::ByteStr;
57    /// let a = ByteStr::new(b"abc");
58    /// let b = ByteStr::new(&b"abc"[..]);
59    /// let c = ByteStr::new("abc");
60    ///
61    /// assert_eq!(a, b);
62    /// assert_eq!(a, c);
63    /// ```
64    #[inline]
65    #[unstable(feature = "bstr", issue = "134915")]
66    pub fn new<B: ?Sized + AsRef<[u8]>>(bytes: &B) -> &Self {
67        ByteStr::from_bytes(bytes.as_ref())
68    }
69
70    #[doc(hidden)]
71    #[unstable(feature = "bstr_internals", issue = "none")]
72    #[inline]
73    pub fn from_bytes(slice: &[u8]) -> &Self {
74        // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`, so we can turn a reference to
75        // the wrapped type into a reference to the wrapper type.
76        unsafe { &*(slice as *const [u8] as *const Self) }
77    }
78
79    #[doc(hidden)]
80    #[unstable(feature = "bstr_internals", issue = "none")]
81    #[inline]
82    pub fn from_bytes_mut(slice: &mut [u8]) -> &mut Self {
83        // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`, so we can turn a reference to
84        // the wrapped type into a reference to the wrapper type.
85        unsafe { &mut *(slice as *mut [u8] as *mut Self) }
86    }
87
88    #[doc(hidden)]
89    #[unstable(feature = "bstr_internals", issue = "none")]
90    #[inline]
91    pub fn as_bytes(&self) -> &[u8] {
92        &self.0
93    }
94
95    #[doc(hidden)]
96    #[unstable(feature = "bstr_internals", issue = "none")]
97    #[inline]
98    pub fn as_bytes_mut(&mut self) -> &mut [u8] {
99        &mut self.0
100    }
101}
102
103#[unstable(feature = "bstr", issue = "134915")]
104impl Deref for ByteStr {
105    type Target = [u8];
106
107    #[inline]
108    fn deref(&self) -> &[u8] {
109        &self.0
110    }
111}
112
113#[unstable(feature = "bstr", issue = "134915")]
114impl DerefMut for ByteStr {
115    #[inline]
116    fn deref_mut(&mut self) -> &mut [u8] {
117        &mut self.0
118    }
119}
120
121#[unstable(feature = "deref_pure_trait", issue = "87121")]
122unsafe impl DerefPure for ByteStr {}
123
124#[unstable(feature = "bstr", issue = "134915")]
125impl fmt::Debug for ByteStr {
126    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127        write!(f, "\"")?;
128        for chunk in self.utf8_chunks() {
129            for c in chunk.valid().chars() {
130                match c {
131                    '\0' => write!(f, "\\0")?,
132                    '\x01'..='\x7f' => write!(f, "{}", (c as u8).escape_ascii())?,
133                    _ => write!(f, "{}", c.escape_debug())?,
134                }
135            }
136            write!(f, "{}", chunk.invalid().escape_ascii())?;
137        }
138        write!(f, "\"")?;
139        Ok(())
140    }
141}
142
143#[unstable(feature = "bstr", issue = "134915")]
144impl fmt::Display for ByteStr {
145    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
146        fn fmt_nopad(this: &ByteStr, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147            for chunk in this.utf8_chunks() {
148                f.write_str(chunk.valid())?;
149                if !chunk.invalid().is_empty() {
150                    f.write_str("\u{FFFD}")?;
151                }
152            }
153            Ok(())
154        }
155
156        let Some(align) = f.align() else {
157            return fmt_nopad(self, f);
158        };
159        let nchars: usize = self
160            .utf8_chunks()
161            .map(|chunk| {
162                chunk.valid().chars().count() + if chunk.invalid().is_empty() { 0 } else { 1 }
163            })
164            .sum();
165        let padding = f.width().unwrap_or(0).saturating_sub(nchars);
166        let fill = f.fill();
167        let (lpad, rpad) = match align {
168            fmt::Alignment::Left => (0, padding),
169            fmt::Alignment::Right => (padding, 0),
170            fmt::Alignment::Center => {
171                let half = padding / 2;
172                (half, half + padding % 2)
173            }
174        };
175        for _ in 0..lpad {
176            write!(f, "{fill}")?;
177        }
178        fmt_nopad(self, f)?;
179        for _ in 0..rpad {
180            write!(f, "{fill}")?;
181        }
182
183        Ok(())
184    }
185}
186
187#[unstable(feature = "bstr", issue = "134915")]
188impl AsRef<[u8]> for ByteStr {
189    #[inline]
190    fn as_ref(&self) -> &[u8] {
191        &self.0
192    }
193}
194
195#[unstable(feature = "bstr", issue = "134915")]
196impl AsRef<ByteStr> for ByteStr {
197    #[inline]
198    fn as_ref(&self) -> &ByteStr {
199        self
200    }
201}
202
203// `impl AsRef<ByteStr> for [u8]` omitted to avoid widespread inference failures
204
205#[unstable(feature = "bstr", issue = "134915")]
206impl AsRef<ByteStr> for str {
207    #[inline]
208    fn as_ref(&self) -> &ByteStr {
209        ByteStr::new(self)
210    }
211}
212
213#[unstable(feature = "bstr", issue = "134915")]
214impl AsMut<[u8]> for ByteStr {
215    #[inline]
216    fn as_mut(&mut self) -> &mut [u8] {
217        &mut self.0
218    }
219}
220
221// `impl AsMut<ByteStr> for [u8]` omitted to avoid widespread inference failures
222
223// `impl Borrow<ByteStr> for [u8]` omitted to avoid widespread inference failures
224
225// `impl Borrow<ByteStr> for str` omitted to avoid widespread inference failures
226
227#[unstable(feature = "bstr", issue = "134915")]
228impl Borrow<[u8]> for ByteStr {
229    #[inline]
230    fn borrow(&self) -> &[u8] {
231        &self.0
232    }
233}
234
235// `impl BorrowMut<ByteStr> for [u8]` omitted to avoid widespread inference failures
236
237#[unstable(feature = "bstr", issue = "134915")]
238impl BorrowMut<[u8]> for ByteStr {
239    #[inline]
240    fn borrow_mut(&mut self) -> &mut [u8] {
241        &mut self.0
242    }
243}
244
245#[unstable(feature = "bstr", issue = "134915")]
246impl<'a> Default for &'a ByteStr {
247    fn default() -> Self {
248        ByteStr::from_bytes(b"")
249    }
250}
251
252#[unstable(feature = "bstr", issue = "134915")]
253impl<'a> Default for &'a mut ByteStr {
254    fn default() -> Self {
255        ByteStr::from_bytes_mut(&mut [])
256    }
257}
258
259// Omitted due to inference failures
260//
261// #[unstable(feature = "bstr", issue = "134915")]
262// impl<'a, const N: usize> From<&'a [u8; N]> for &'a ByteStr {
263//     #[inline]
264//     fn from(s: &'a [u8; N]) -> Self {
265//         ByteStr::from_bytes(s)
266//     }
267// }
268//
269// #[unstable(feature = "bstr", issue = "134915")]
270// impl<'a> From<&'a [u8]> for &'a ByteStr {
271//     #[inline]
272//     fn from(s: &'a [u8]) -> Self {
273//         ByteStr::from_bytes(s)
274//     }
275// }
276
277// Omitted due to slice-from-array-issue-113238:
278//
279// #[unstable(feature = "bstr", issue = "134915")]
280// impl<'a> From<&'a ByteStr> for &'a [u8] {
281//     #[inline]
282//     fn from(s: &'a ByteStr) -> Self {
283//         &s.0
284//     }
285// }
286//
287// #[unstable(feature = "bstr", issue = "134915")]
288// impl<'a> From<&'a mut ByteStr> for &'a mut [u8] {
289//     #[inline]
290//     fn from(s: &'a mut ByteStr) -> Self {
291//         &mut s.0
292//     }
293// }
294
295// Omitted due to inference failures
296//
297// #[unstable(feature = "bstr", issue = "134915")]
298// impl<'a> From<&'a str> for &'a ByteStr {
299//     #[inline]
300//     fn from(s: &'a str) -> Self {
301//         ByteStr::from_bytes(s.as_bytes())
302//     }
303// }
304
305#[unstable(feature = "bstr", issue = "134915")]
306impl<'a> TryFrom<&'a ByteStr> for &'a str {
307    type Error = crate::str::Utf8Error;
308
309    #[inline]
310    fn try_from(s: &'a ByteStr) -> Result<Self, Self::Error> {
311        crate::str::from_utf8(&s.0)
312    }
313}
314
315#[unstable(feature = "bstr", issue = "134915")]
316impl<'a> TryFrom<&'a mut ByteStr> for &'a mut str {
317    type Error = crate::str::Utf8Error;
318
319    #[inline]
320    fn try_from(s: &'a mut ByteStr) -> Result<Self, Self::Error> {
321        crate::str::from_utf8_mut(&mut s.0)
322    }
323}