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    #[rustc_const_unstable(feature = "const_convert", issue = "143773")]
67    pub const fn new<B: ?Sized + [const] AsRef<[u8]>>(bytes: &B) -> &Self {
68        ByteStr::from_bytes(bytes.as_ref())
69    }
70
71    #[doc(hidden)]
72    #[unstable(feature = "bstr_internals", issue = "none")]
73    #[inline]
74    #[rustc_const_unstable(feature = "bstr_internals", issue = "none")]
75    pub const fn from_bytes(slice: &[u8]) -> &Self {
76        // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`, so we can turn a reference to
77        // the wrapped type into a reference to the wrapper type.
78        unsafe { &*(slice as *const [u8] as *const Self) }
79    }
80
81    #[doc(hidden)]
82    #[unstable(feature = "bstr_internals", issue = "none")]
83    #[inline]
84    #[rustc_const_unstable(feature = "bstr_internals", issue = "none")]
85    pub const fn from_bytes_mut(slice: &mut [u8]) -> &mut Self {
86        // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`, so we can turn a reference to
87        // the wrapped type into a reference to the wrapper type.
88        unsafe { &mut *(slice as *mut [u8] as *mut Self) }
89    }
90
91    #[doc(hidden)]
92    #[unstable(feature = "bstr_internals", issue = "none")]
93    #[inline]
94    #[rustc_const_unstable(feature = "bstr_internals", issue = "none")]
95    pub const fn as_bytes(&self) -> &[u8] {
96        &self.0
97    }
98
99    #[doc(hidden)]
100    #[unstable(feature = "bstr_internals", issue = "none")]
101    #[inline]
102    #[rustc_const_unstable(feature = "bstr_internals", issue = "none")]
103    pub const fn as_bytes_mut(&mut self) -> &mut [u8] {
104        &mut self.0
105    }
106}
107
108#[unstable(feature = "bstr", issue = "134915")]
109#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
110impl const Deref for ByteStr {
111    type Target = [u8];
112
113    #[inline]
114    fn deref(&self) -> &[u8] {
115        &self.0
116    }
117}
118
119#[unstable(feature = "bstr", issue = "134915")]
120#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
121impl const DerefMut for ByteStr {
122    #[inline]
123    fn deref_mut(&mut self) -> &mut [u8] {
124        &mut self.0
125    }
126}
127
128#[unstable(feature = "deref_pure_trait", issue = "87121")]
129unsafe impl DerefPure for ByteStr {}
130
131#[unstable(feature = "bstr", issue = "134915")]
132impl fmt::Debug for ByteStr {
133    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134        write!(f, "\"")?;
135        for chunk in self.utf8_chunks() {
136            for c in chunk.valid().chars() {
137                match c {
138                    '\0' => write!(f, "\\0")?,
139                    '\x01'..='\x7f' => write!(f, "{}", (c as u8).escape_ascii())?,
140                    _ => write!(f, "{}", c.escape_debug())?,
141                }
142            }
143            write!(f, "{}", chunk.invalid().escape_ascii())?;
144        }
145        write!(f, "\"")?;
146        Ok(())
147    }
148}
149
150#[unstable(feature = "bstr", issue = "134915")]
151impl fmt::Display for ByteStr {
152    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
153        fn fmt_nopad(this: &ByteStr, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154            for chunk in this.utf8_chunks() {
155                f.write_str(chunk.valid())?;
156                if !chunk.invalid().is_empty() {
157                    f.write_str("\u{FFFD}")?;
158                }
159            }
160            Ok(())
161        }
162
163        let Some(align) = f.align() else {
164            return fmt_nopad(self, f);
165        };
166        let nchars: usize = self
167            .utf8_chunks()
168            .map(|chunk| {
169                chunk.valid().chars().count() + if chunk.invalid().is_empty() { 0 } else { 1 }
170            })
171            .sum();
172        let padding = f.width().unwrap_or(0).saturating_sub(nchars);
173        let fill = f.fill();
174        let (lpad, rpad) = match align {
175            fmt::Alignment::Left => (0, padding),
176            fmt::Alignment::Right => (padding, 0),
177            fmt::Alignment::Center => {
178                let half = padding / 2;
179                (half, half + padding % 2)
180            }
181        };
182        for _ in 0..lpad {
183            write!(f, "{fill}")?;
184        }
185        fmt_nopad(self, f)?;
186        for _ in 0..rpad {
187            write!(f, "{fill}")?;
188        }
189
190        Ok(())
191    }
192}
193
194#[unstable(feature = "bstr", issue = "134915")]
195#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
196impl const AsRef<[u8]> for ByteStr {
197    #[inline]
198    fn as_ref(&self) -> &[u8] {
199        &self.0
200    }
201}
202
203#[unstable(feature = "bstr", issue = "134915")]
204#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
205impl const AsRef<ByteStr> for ByteStr {
206    #[inline]
207    fn as_ref(&self) -> &ByteStr {
208        self
209    }
210}
211
212// `impl AsRef<ByteStr> for [u8]` omitted to avoid widespread inference failures
213
214#[unstable(feature = "bstr", issue = "134915")]
215#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
216impl const AsRef<ByteStr> for str {
217    #[inline]
218    fn as_ref(&self) -> &ByteStr {
219        ByteStr::new(self)
220    }
221}
222
223#[unstable(feature = "bstr", issue = "134915")]
224#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
225impl const AsMut<[u8]> for ByteStr {
226    #[inline]
227    fn as_mut(&mut self) -> &mut [u8] {
228        &mut self.0
229    }
230}
231
232// `impl AsMut<ByteStr> for [u8]` omitted to avoid widespread inference failures
233
234// `impl Borrow<ByteStr> for [u8]` omitted to avoid widespread inference failures
235
236// `impl Borrow<ByteStr> for str` omitted to avoid widespread inference failures
237
238#[unstable(feature = "bstr", issue = "134915")]
239#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
240impl const Borrow<[u8]> for ByteStr {
241    #[inline]
242    fn borrow(&self) -> &[u8] {
243        &self.0
244    }
245}
246
247// `impl BorrowMut<ByteStr> for [u8]` omitted to avoid widespread inference failures
248
249#[unstable(feature = "bstr", issue = "134915")]
250#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
251impl const BorrowMut<[u8]> for ByteStr {
252    #[inline]
253    fn borrow_mut(&mut self) -> &mut [u8] {
254        &mut self.0
255    }
256}
257
258#[unstable(feature = "bstr", issue = "134915")]
259impl<'a> Default for &'a ByteStr {
260    fn default() -> Self {
261        ByteStr::from_bytes(b"")
262    }
263}
264
265#[unstable(feature = "bstr", issue = "134915")]
266impl<'a> Default for &'a mut ByteStr {
267    fn default() -> Self {
268        ByteStr::from_bytes_mut(&mut [])
269    }
270}
271
272// Omitted due to inference failures
273//
274// #[unstable(feature = "bstr", issue = "134915")]
275// impl<'a, const N: usize> From<&'a [u8; N]> for &'a ByteStr {
276//     #[inline]
277//     fn from(s: &'a [u8; N]) -> Self {
278//         ByteStr::from_bytes(s)
279//     }
280// }
281//
282// #[unstable(feature = "bstr", issue = "134915")]
283// impl<'a> From<&'a [u8]> for &'a ByteStr {
284//     #[inline]
285//     fn from(s: &'a [u8]) -> Self {
286//         ByteStr::from_bytes(s)
287//     }
288// }
289
290// Omitted due to slice-from-array-issue-113238:
291//
292// #[unstable(feature = "bstr", issue = "134915")]
293// impl<'a> From<&'a ByteStr> for &'a [u8] {
294//     #[inline]
295//     fn from(s: &'a ByteStr) -> Self {
296//         &s.0
297//     }
298// }
299//
300// #[unstable(feature = "bstr", issue = "134915")]
301// impl<'a> From<&'a mut ByteStr> for &'a mut [u8] {
302//     #[inline]
303//     fn from(s: &'a mut ByteStr) -> Self {
304//         &mut s.0
305//     }
306// }
307
308// Omitted due to inference failures
309//
310// #[unstable(feature = "bstr", issue = "134915")]
311// impl<'a> From<&'a str> for &'a ByteStr {
312//     #[inline]
313//     fn from(s: &'a str) -> Self {
314//         ByteStr::from_bytes(s.as_bytes())
315//     }
316// }
317
318#[unstable(feature = "bstr", issue = "134915")]
319#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
320impl<'a> const TryFrom<&'a ByteStr> for &'a str {
321    type Error = crate::str::Utf8Error;
322
323    #[inline]
324    fn try_from(s: &'a ByteStr) -> Result<Self, Self::Error> {
325        crate::str::from_utf8(&s.0)
326    }
327}
328
329#[unstable(feature = "bstr", issue = "134915")]
330#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
331impl<'a> const TryFrom<&'a mut ByteStr> for &'a mut str {
332    type Error = crate::str::Utf8Error;
333
334    #[inline]
335    fn try_from(s: &'a mut ByteStr) -> Result<Self, Self::Error> {
336        crate::str::from_utf8_mut(&mut s.0)
337    }
338}