Skip to main content

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