core/
bstr.rs

1//! The `ByteStr` type and trait implementations.
2
3use crate::borrow::{Borrow, BorrowMut};
4use crate::cmp::Ordering;
5use crate::ops::{
6    Deref, DerefMut, DerefPure, Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive,
7    RangeTo, RangeToInclusive,
8};
9use crate::{fmt, hash};
10
11/// A wrapper for `&[u8]` representing a human-readable string that's conventionally, but not
12/// always, UTF-8.
13///
14/// Unlike `&str`, this type permits non-UTF-8 contents, making it suitable for user input,
15/// non-native filenames (as `Path` only supports native filenames), and other applications that
16/// need to round-trip whatever data the user provides.
17///
18/// For an owned, growable byte string buffer, use
19/// [`ByteString`](../../std/bstr/struct.ByteString.html).
20///
21/// `ByteStr` implements `Deref` to `[u8]`, so all methods available on `[u8]` are available on
22/// `ByteStr`.
23///
24/// # Representation
25///
26/// A `&ByteStr` has the same representation as a `&str`. That is, a `&ByteStr` is a wide pointer
27/// which includes a pointer to some bytes and a length.
28///
29/// # Trait implementations
30///
31/// The `ByteStr` type has a number of trait implementations, and in particular, defines equality
32/// and comparisons between `&ByteStr`, `&str`, and `&[u8]`, for convenience.
33///
34/// The `Debug` implementation for `ByteStr` shows its bytes as a normal string, with invalid UTF-8
35/// presented as hex escape sequences.
36///
37/// The `Display` implementation behaves as if the `ByteStr` were first lossily converted to a
38/// `str`, with invalid UTF-8 presented as the Unicode replacement character: �
39///
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
96#[unstable(feature = "bstr", issue = "134915")]
97impl Deref for ByteStr {
98    type Target = [u8];
99
100    #[inline]
101    fn deref(&self) -> &[u8] {
102        &self.0
103    }
104}
105
106#[unstable(feature = "bstr", issue = "134915")]
107impl DerefMut for ByteStr {
108    #[inline]
109    fn deref_mut(&mut self) -> &mut [u8] {
110        &mut self.0
111    }
112}
113
114#[unstable(feature = "deref_pure_trait", issue = "87121")]
115unsafe impl DerefPure for ByteStr {}
116
117#[unstable(feature = "bstr", issue = "134915")]
118impl fmt::Debug for ByteStr {
119    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120        write!(f, "\"")?;
121        for chunk in self.utf8_chunks() {
122            for c in chunk.valid().chars() {
123                match c {
124                    '\0' => write!(f, "\\0")?,
125                    '\x01'..='\x7f' => write!(f, "{}", (c as u8).escape_ascii())?,
126                    _ => write!(f, "{}", c.escape_debug())?,
127                }
128            }
129            write!(f, "{}", chunk.invalid().escape_ascii())?;
130        }
131        write!(f, "\"")?;
132        Ok(())
133    }
134}
135
136#[unstable(feature = "bstr", issue = "134915")]
137impl fmt::Display for ByteStr {
138    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139        fn fmt_nopad(this: &ByteStr, f: &mut fmt::Formatter<'_>) -> fmt::Result {
140            for chunk in this.utf8_chunks() {
141                f.write_str(chunk.valid())?;
142                if !chunk.invalid().is_empty() {
143                    f.write_str("\u{FFFD}")?;
144                }
145            }
146            Ok(())
147        }
148
149        let Some(align) = f.align() else {
150            return fmt_nopad(self, f);
151        };
152        let nchars: usize = self
153            .utf8_chunks()
154            .map(|chunk| chunk.valid().len() + if chunk.invalid().is_empty() { 0 } else { 1 })
155            .sum();
156        let padding = f.width().unwrap_or(0).saturating_sub(nchars);
157        let fill = f.fill();
158        let (lpad, rpad) = match align {
159            fmt::Alignment::Left => (0, padding),
160            fmt::Alignment::Right => (padding, 0),
161            fmt::Alignment::Center => {
162                let half = padding / 2;
163                (half, half + padding % 2)
164            }
165        };
166        for _ in 0..lpad {
167            write!(f, "{fill}")?;
168        }
169        fmt_nopad(self, f)?;
170        for _ in 0..rpad {
171            write!(f, "{fill}")?;
172        }
173
174        Ok(())
175    }
176}
177
178#[unstable(feature = "bstr", issue = "134915")]
179impl AsRef<[u8]> for ByteStr {
180    #[inline]
181    fn as_ref(&self) -> &[u8] {
182        &self.0
183    }
184}
185
186#[unstable(feature = "bstr", issue = "134915")]
187impl AsRef<ByteStr> for ByteStr {
188    #[inline]
189    fn as_ref(&self) -> &ByteStr {
190        self
191    }
192}
193
194// `impl AsRef<ByteStr> for [u8]` omitted to avoid widespread inference failures
195
196#[unstable(feature = "bstr", issue = "134915")]
197impl AsRef<ByteStr> for str {
198    #[inline]
199    fn as_ref(&self) -> &ByteStr {
200        ByteStr::new(self)
201    }
202}
203
204#[unstable(feature = "bstr", issue = "134915")]
205impl AsMut<[u8]> for ByteStr {
206    #[inline]
207    fn as_mut(&mut self) -> &mut [u8] {
208        &mut self.0
209    }
210}
211
212// `impl AsMut<ByteStr> for [u8]` omitted to avoid widespread inference failures
213
214// `impl Borrow<ByteStr> for [u8]` omitted to avoid widespread inference failures
215
216// `impl Borrow<ByteStr> for str` omitted to avoid widespread inference failures
217
218#[unstable(feature = "bstr", issue = "134915")]
219impl Borrow<[u8]> for ByteStr {
220    #[inline]
221    fn borrow(&self) -> &[u8] {
222        &self.0
223    }
224}
225
226// `impl BorrowMut<ByteStr> for [u8]` omitted to avoid widespread inference failures
227
228#[unstable(feature = "bstr", issue = "134915")]
229impl BorrowMut<[u8]> for ByteStr {
230    #[inline]
231    fn borrow_mut(&mut self) -> &mut [u8] {
232        &mut self.0
233    }
234}
235
236#[unstable(feature = "bstr", issue = "134915")]
237impl<'a> Default for &'a ByteStr {
238    fn default() -> Self {
239        ByteStr::from_bytes(b"")
240    }
241}
242
243#[unstable(feature = "bstr", issue = "134915")]
244impl<'a> Default for &'a mut ByteStr {
245    fn default() -> Self {
246        ByteStr::from_bytes_mut(&mut [])
247    }
248}
249
250// Omitted due to inference failures
251//
252// #[unstable(feature = "bstr", issue = "134915")]
253// impl<'a, const N: usize> From<&'a [u8; N]> for &'a ByteStr {
254//     #[inline]
255//     fn from(s: &'a [u8; N]) -> Self {
256//         ByteStr::from_bytes(s)
257//     }
258// }
259//
260// #[unstable(feature = "bstr", issue = "134915")]
261// impl<'a> From<&'a [u8]> for &'a ByteStr {
262//     #[inline]
263//     fn from(s: &'a [u8]) -> Self {
264//         ByteStr::from_bytes(s)
265//     }
266// }
267
268// Omitted due to slice-from-array-issue-113238:
269//
270// #[unstable(feature = "bstr", issue = "134915")]
271// impl<'a> From<&'a ByteStr> for &'a [u8] {
272//     #[inline]
273//     fn from(s: &'a ByteStr) -> Self {
274//         &s.0
275//     }
276// }
277//
278// #[unstable(feature = "bstr", issue = "134915")]
279// impl<'a> From<&'a mut ByteStr> for &'a mut [u8] {
280//     #[inline]
281//     fn from(s: &'a mut ByteStr) -> Self {
282//         &mut s.0
283//     }
284// }
285
286// Omitted due to inference failures
287//
288// #[unstable(feature = "bstr", issue = "134915")]
289// impl<'a> From<&'a str> for &'a ByteStr {
290//     #[inline]
291//     fn from(s: &'a str) -> Self {
292//         ByteStr::from_bytes(s.as_bytes())
293//     }
294// }
295
296#[unstable(feature = "bstr", issue = "134915")]
297impl hash::Hash for ByteStr {
298    #[inline]
299    fn hash<H: hash::Hasher>(&self, state: &mut H) {
300        self.0.hash(state);
301    }
302}
303
304#[unstable(feature = "bstr", issue = "134915")]
305impl Index<usize> for ByteStr {
306    type Output = u8;
307
308    #[inline]
309    fn index(&self, idx: usize) -> &u8 {
310        &self.0[idx]
311    }
312}
313
314#[unstable(feature = "bstr", issue = "134915")]
315impl Index<RangeFull> for ByteStr {
316    type Output = ByteStr;
317
318    #[inline]
319    fn index(&self, _: RangeFull) -> &ByteStr {
320        self
321    }
322}
323
324#[unstable(feature = "bstr", issue = "134915")]
325impl Index<Range<usize>> for ByteStr {
326    type Output = ByteStr;
327
328    #[inline]
329    fn index(&self, r: Range<usize>) -> &ByteStr {
330        ByteStr::from_bytes(&self.0[r])
331    }
332}
333
334#[unstable(feature = "bstr", issue = "134915")]
335impl Index<RangeInclusive<usize>> for ByteStr {
336    type Output = ByteStr;
337
338    #[inline]
339    fn index(&self, r: RangeInclusive<usize>) -> &ByteStr {
340        ByteStr::from_bytes(&self.0[r])
341    }
342}
343
344#[unstable(feature = "bstr", issue = "134915")]
345impl Index<RangeFrom<usize>> for ByteStr {
346    type Output = ByteStr;
347
348    #[inline]
349    fn index(&self, r: RangeFrom<usize>) -> &ByteStr {
350        ByteStr::from_bytes(&self.0[r])
351    }
352}
353
354#[unstable(feature = "bstr", issue = "134915")]
355impl Index<RangeTo<usize>> for ByteStr {
356    type Output = ByteStr;
357
358    #[inline]
359    fn index(&self, r: RangeTo<usize>) -> &ByteStr {
360        ByteStr::from_bytes(&self.0[r])
361    }
362}
363
364#[unstable(feature = "bstr", issue = "134915")]
365impl Index<RangeToInclusive<usize>> for ByteStr {
366    type Output = ByteStr;
367
368    #[inline]
369    fn index(&self, r: RangeToInclusive<usize>) -> &ByteStr {
370        ByteStr::from_bytes(&self.0[r])
371    }
372}
373
374#[unstable(feature = "bstr", issue = "134915")]
375impl IndexMut<usize> for ByteStr {
376    #[inline]
377    fn index_mut(&mut self, idx: usize) -> &mut u8 {
378        &mut self.0[idx]
379    }
380}
381
382#[unstable(feature = "bstr", issue = "134915")]
383impl IndexMut<RangeFull> for ByteStr {
384    #[inline]
385    fn index_mut(&mut self, _: RangeFull) -> &mut ByteStr {
386        self
387    }
388}
389
390#[unstable(feature = "bstr", issue = "134915")]
391impl IndexMut<Range<usize>> for ByteStr {
392    #[inline]
393    fn index_mut(&mut self, r: Range<usize>) -> &mut ByteStr {
394        ByteStr::from_bytes_mut(&mut self.0[r])
395    }
396}
397
398#[unstable(feature = "bstr", issue = "134915")]
399impl IndexMut<RangeInclusive<usize>> for ByteStr {
400    #[inline]
401    fn index_mut(&mut self, r: RangeInclusive<usize>) -> &mut ByteStr {
402        ByteStr::from_bytes_mut(&mut self.0[r])
403    }
404}
405
406#[unstable(feature = "bstr", issue = "134915")]
407impl IndexMut<RangeFrom<usize>> for ByteStr {
408    #[inline]
409    fn index_mut(&mut self, r: RangeFrom<usize>) -> &mut ByteStr {
410        ByteStr::from_bytes_mut(&mut self.0[r])
411    }
412}
413
414#[unstable(feature = "bstr", issue = "134915")]
415impl IndexMut<RangeTo<usize>> for ByteStr {
416    #[inline]
417    fn index_mut(&mut self, r: RangeTo<usize>) -> &mut ByteStr {
418        ByteStr::from_bytes_mut(&mut self.0[r])
419    }
420}
421
422#[unstable(feature = "bstr", issue = "134915")]
423impl IndexMut<RangeToInclusive<usize>> for ByteStr {
424    #[inline]
425    fn index_mut(&mut self, r: RangeToInclusive<usize>) -> &mut ByteStr {
426        ByteStr::from_bytes_mut(&mut self.0[r])
427    }
428}
429
430#[unstable(feature = "bstr", issue = "134915")]
431impl Eq for ByteStr {}
432
433#[unstable(feature = "bstr", issue = "134915")]
434impl PartialEq<ByteStr> for ByteStr {
435    #[inline]
436    fn eq(&self, other: &ByteStr) -> bool {
437        &self.0 == &other.0
438    }
439}
440
441#[doc(hidden)]
442#[macro_export]
443#[unstable(feature = "bstr_internals", issue = "none")]
444macro_rules! impl_partial_eq {
445    ($lhs:ty, $rhs:ty) => {
446        #[allow(unused_lifetimes)]
447        impl<'a> PartialEq<$rhs> for $lhs {
448            #[inline]
449            fn eq(&self, other: &$rhs) -> bool {
450                let other: &[u8] = other.as_ref();
451                PartialEq::eq(self.as_bytes(), other)
452            }
453        }
454
455        #[allow(unused_lifetimes)]
456        impl<'a> PartialEq<$lhs> for $rhs {
457            #[inline]
458            fn eq(&self, other: &$lhs) -> bool {
459                let this: &[u8] = self.as_ref();
460                PartialEq::eq(this, other.as_bytes())
461            }
462        }
463    };
464}
465
466#[doc(hidden)]
467#[unstable(feature = "bstr_internals", issue = "none")]
468pub use impl_partial_eq;
469
470#[doc(hidden)]
471#[macro_export]
472#[unstable(feature = "bstr_internals", issue = "none")]
473macro_rules! impl_partial_eq_ord {
474    ($lhs:ty, $rhs:ty) => {
475        $crate::bstr::impl_partial_eq!($lhs, $rhs);
476
477        #[allow(unused_lifetimes)]
478        #[unstable(feature = "bstr", issue = "134915")]
479        impl<'a> PartialOrd<$rhs> for $lhs {
480            #[inline]
481            fn partial_cmp(&self, other: &$rhs) -> Option<Ordering> {
482                let other: &[u8] = other.as_ref();
483                PartialOrd::partial_cmp(self.as_bytes(), other)
484            }
485        }
486
487        #[allow(unused_lifetimes)]
488        #[unstable(feature = "bstr", issue = "134915")]
489        impl<'a> PartialOrd<$lhs> for $rhs {
490            #[inline]
491            fn partial_cmp(&self, other: &$lhs) -> Option<Ordering> {
492                let this: &[u8] = self.as_ref();
493                PartialOrd::partial_cmp(this, other.as_bytes())
494            }
495        }
496    };
497}
498
499#[doc(hidden)]
500#[unstable(feature = "bstr_internals", issue = "none")]
501pub use impl_partial_eq_ord;
502
503#[doc(hidden)]
504#[macro_export]
505#[unstable(feature = "bstr_internals", issue = "none")]
506macro_rules! impl_partial_eq_n {
507    ($lhs:ty, $rhs:ty) => {
508        #[allow(unused_lifetimes)]
509        #[unstable(feature = "bstr", issue = "134915")]
510        impl<const N: usize> PartialEq<$rhs> for $lhs {
511            #[inline]
512            fn eq(&self, other: &$rhs) -> bool {
513                let other: &[u8] = other.as_ref();
514                PartialEq::eq(self.as_bytes(), other)
515            }
516        }
517
518        #[allow(unused_lifetimes)]
519        #[unstable(feature = "bstr", issue = "134915")]
520        impl<const N: usize> PartialEq<$lhs> for $rhs {
521            #[inline]
522            fn eq(&self, other: &$lhs) -> bool {
523                let this: &[u8] = self.as_ref();
524                PartialEq::eq(this, other.as_bytes())
525            }
526        }
527    };
528}
529
530#[doc(hidden)]
531#[unstable(feature = "bstr_internals", issue = "none")]
532pub use impl_partial_eq_n;
533
534// PartialOrd with `[u8]` omitted to avoid inference failures
535impl_partial_eq!(ByteStr, [u8]);
536// PartialOrd with `&[u8]` omitted to avoid inference failures
537impl_partial_eq!(ByteStr, &[u8]);
538// PartialOrd with `str` omitted to avoid inference failures
539impl_partial_eq!(ByteStr, str);
540// PartialOrd with `&str` omitted to avoid inference failures
541impl_partial_eq!(ByteStr, &str);
542// PartialOrd with `[u8; N]` omitted to avoid inference failures
543impl_partial_eq_n!(ByteStr, [u8; N]);
544// PartialOrd with `[u8; N]` omitted to avoid inference failures
545impl_partial_eq_n!(ByteStr, &[u8; N]);
546
547#[unstable(feature = "bstr", issue = "134915")]
548impl Ord for ByteStr {
549    #[inline]
550    fn cmp(&self, other: &ByteStr) -> Ordering {
551        Ord::cmp(&self.0, &other.0)
552    }
553}
554
555#[unstable(feature = "bstr", issue = "134915")]
556impl PartialOrd for ByteStr {
557    #[inline]
558    fn partial_cmp(&self, other: &ByteStr) -> Option<Ordering> {
559        PartialOrd::partial_cmp(&self.0, &other.0)
560    }
561}
562
563#[unstable(feature = "bstr", issue = "134915")]
564impl<'a> TryFrom<&'a ByteStr> for &'a str {
565    type Error = crate::str::Utf8Error;
566
567    #[inline]
568    fn try_from(s: &'a ByteStr) -> Result<Self, Self::Error> {
569        crate::str::from_utf8(&s.0)
570    }
571}
572
573#[unstable(feature = "bstr", issue = "134915")]
574impl<'a> TryFrom<&'a mut ByteStr> for &'a mut str {
575    type Error = crate::str::Utf8Error;
576
577    #[inline]
578    fn try_from(s: &'a mut ByteStr) -> Result<Self, Self::Error> {
579        crate::str::from_utf8_mut(&mut s.0)
580    }
581}