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