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| {
155                chunk.valid().chars().count() + if chunk.invalid().is_empty() { 0 } else { 1 }
156            })
157            .sum();
158        let padding = f.width().unwrap_or(0).saturating_sub(nchars);
159        let fill = f.fill();
160        let (lpad, rpad) = match align {
161            fmt::Alignment::Left => (0, padding),
162            fmt::Alignment::Right => (padding, 0),
163            fmt::Alignment::Center => {
164                let half = padding / 2;
165                (half, half + padding % 2)
166            }
167        };
168        for _ in 0..lpad {
169            write!(f, "{fill}")?;
170        }
171        fmt_nopad(self, f)?;
172        for _ in 0..rpad {
173            write!(f, "{fill}")?;
174        }
175
176        Ok(())
177    }
178}
179
180#[unstable(feature = "bstr", issue = "134915")]
181impl AsRef<[u8]> for ByteStr {
182    #[inline]
183    fn as_ref(&self) -> &[u8] {
184        &self.0
185    }
186}
187
188#[unstable(feature = "bstr", issue = "134915")]
189impl AsRef<ByteStr> for ByteStr {
190    #[inline]
191    fn as_ref(&self) -> &ByteStr {
192        self
193    }
194}
195
196// `impl AsRef<ByteStr> for [u8]` omitted to avoid widespread inference failures
197
198#[unstable(feature = "bstr", issue = "134915")]
199impl AsRef<ByteStr> for str {
200    #[inline]
201    fn as_ref(&self) -> &ByteStr {
202        ByteStr::new(self)
203    }
204}
205
206#[unstable(feature = "bstr", issue = "134915")]
207impl AsMut<[u8]> for ByteStr {
208    #[inline]
209    fn as_mut(&mut self) -> &mut [u8] {
210        &mut self.0
211    }
212}
213
214// `impl AsMut<ByteStr> for [u8]` omitted to avoid widespread inference failures
215
216// `impl Borrow<ByteStr> for [u8]` omitted to avoid widespread inference failures
217
218// `impl Borrow<ByteStr> for str` omitted to avoid widespread inference failures
219
220#[unstable(feature = "bstr", issue = "134915")]
221impl Borrow<[u8]> for ByteStr {
222    #[inline]
223    fn borrow(&self) -> &[u8] {
224        &self.0
225    }
226}
227
228// `impl BorrowMut<ByteStr> for [u8]` omitted to avoid widespread inference failures
229
230#[unstable(feature = "bstr", issue = "134915")]
231impl BorrowMut<[u8]> for ByteStr {
232    #[inline]
233    fn borrow_mut(&mut self) -> &mut [u8] {
234        &mut self.0
235    }
236}
237
238#[unstable(feature = "bstr", issue = "134915")]
239impl<'a> Default for &'a ByteStr {
240    fn default() -> Self {
241        ByteStr::from_bytes(b"")
242    }
243}
244
245#[unstable(feature = "bstr", issue = "134915")]
246impl<'a> Default for &'a mut ByteStr {
247    fn default() -> Self {
248        ByteStr::from_bytes_mut(&mut [])
249    }
250}
251
252// Omitted due to inference failures
253//
254// #[unstable(feature = "bstr", issue = "134915")]
255// impl<'a, const N: usize> From<&'a [u8; N]> for &'a ByteStr {
256//     #[inline]
257//     fn from(s: &'a [u8; N]) -> Self {
258//         ByteStr::from_bytes(s)
259//     }
260// }
261//
262// #[unstable(feature = "bstr", issue = "134915")]
263// impl<'a> From<&'a [u8]> for &'a ByteStr {
264//     #[inline]
265//     fn from(s: &'a [u8]) -> Self {
266//         ByteStr::from_bytes(s)
267//     }
268// }
269
270// Omitted due to slice-from-array-issue-113238:
271//
272// #[unstable(feature = "bstr", issue = "134915")]
273// impl<'a> From<&'a ByteStr> for &'a [u8] {
274//     #[inline]
275//     fn from(s: &'a ByteStr) -> Self {
276//         &s.0
277//     }
278// }
279//
280// #[unstable(feature = "bstr", issue = "134915")]
281// impl<'a> From<&'a mut ByteStr> for &'a mut [u8] {
282//     #[inline]
283//     fn from(s: &'a mut ByteStr) -> Self {
284//         &mut s.0
285//     }
286// }
287
288// Omitted due to inference failures
289//
290// #[unstable(feature = "bstr", issue = "134915")]
291// impl<'a> From<&'a str> for &'a ByteStr {
292//     #[inline]
293//     fn from(s: &'a str) -> Self {
294//         ByteStr::from_bytes(s.as_bytes())
295//     }
296// }
297
298#[unstable(feature = "bstr", issue = "134915")]
299impl hash::Hash for ByteStr {
300    #[inline]
301    fn hash<H: hash::Hasher>(&self, state: &mut H) {
302        self.0.hash(state);
303    }
304}
305
306#[unstable(feature = "bstr", issue = "134915")]
307impl Index<usize> for ByteStr {
308    type Output = u8;
309
310    #[inline]
311    fn index(&self, idx: usize) -> &u8 {
312        &self.0[idx]
313    }
314}
315
316#[unstable(feature = "bstr", issue = "134915")]
317impl Index<RangeFull> for ByteStr {
318    type Output = ByteStr;
319
320    #[inline]
321    fn index(&self, _: RangeFull) -> &ByteStr {
322        self
323    }
324}
325
326#[unstable(feature = "bstr", issue = "134915")]
327impl Index<Range<usize>> for ByteStr {
328    type Output = ByteStr;
329
330    #[inline]
331    fn index(&self, r: Range<usize>) -> &ByteStr {
332        ByteStr::from_bytes(&self.0[r])
333    }
334}
335
336#[unstable(feature = "bstr", issue = "134915")]
337impl Index<RangeInclusive<usize>> for ByteStr {
338    type Output = ByteStr;
339
340    #[inline]
341    fn index(&self, r: RangeInclusive<usize>) -> &ByteStr {
342        ByteStr::from_bytes(&self.0[r])
343    }
344}
345
346#[unstable(feature = "bstr", issue = "134915")]
347impl Index<RangeFrom<usize>> for ByteStr {
348    type Output = ByteStr;
349
350    #[inline]
351    fn index(&self, r: RangeFrom<usize>) -> &ByteStr {
352        ByteStr::from_bytes(&self.0[r])
353    }
354}
355
356#[unstable(feature = "bstr", issue = "134915")]
357impl Index<RangeTo<usize>> for ByteStr {
358    type Output = ByteStr;
359
360    #[inline]
361    fn index(&self, r: RangeTo<usize>) -> &ByteStr {
362        ByteStr::from_bytes(&self.0[r])
363    }
364}
365
366#[unstable(feature = "bstr", issue = "134915")]
367impl Index<RangeToInclusive<usize>> for ByteStr {
368    type Output = ByteStr;
369
370    #[inline]
371    fn index(&self, r: RangeToInclusive<usize>) -> &ByteStr {
372        ByteStr::from_bytes(&self.0[r])
373    }
374}
375
376#[unstable(feature = "bstr", issue = "134915")]
377impl IndexMut<usize> for ByteStr {
378    #[inline]
379    fn index_mut(&mut self, idx: usize) -> &mut u8 {
380        &mut self.0[idx]
381    }
382}
383
384#[unstable(feature = "bstr", issue = "134915")]
385impl IndexMut<RangeFull> for ByteStr {
386    #[inline]
387    fn index_mut(&mut self, _: RangeFull) -> &mut ByteStr {
388        self
389    }
390}
391
392#[unstable(feature = "bstr", issue = "134915")]
393impl IndexMut<Range<usize>> for ByteStr {
394    #[inline]
395    fn index_mut(&mut self, r: Range<usize>) -> &mut ByteStr {
396        ByteStr::from_bytes_mut(&mut self.0[r])
397    }
398}
399
400#[unstable(feature = "bstr", issue = "134915")]
401impl IndexMut<RangeInclusive<usize>> for ByteStr {
402    #[inline]
403    fn index_mut(&mut self, r: RangeInclusive<usize>) -> &mut ByteStr {
404        ByteStr::from_bytes_mut(&mut self.0[r])
405    }
406}
407
408#[unstable(feature = "bstr", issue = "134915")]
409impl IndexMut<RangeFrom<usize>> for ByteStr {
410    #[inline]
411    fn index_mut(&mut self, r: RangeFrom<usize>) -> &mut ByteStr {
412        ByteStr::from_bytes_mut(&mut self.0[r])
413    }
414}
415
416#[unstable(feature = "bstr", issue = "134915")]
417impl IndexMut<RangeTo<usize>> for ByteStr {
418    #[inline]
419    fn index_mut(&mut self, r: RangeTo<usize>) -> &mut ByteStr {
420        ByteStr::from_bytes_mut(&mut self.0[r])
421    }
422}
423
424#[unstable(feature = "bstr", issue = "134915")]
425impl IndexMut<RangeToInclusive<usize>> for ByteStr {
426    #[inline]
427    fn index_mut(&mut self, r: RangeToInclusive<usize>) -> &mut ByteStr {
428        ByteStr::from_bytes_mut(&mut self.0[r])
429    }
430}
431
432#[unstable(feature = "bstr", issue = "134915")]
433impl Eq for ByteStr {}
434
435#[unstable(feature = "bstr", issue = "134915")]
436impl PartialEq<ByteStr> for ByteStr {
437    #[inline]
438    fn eq(&self, other: &ByteStr) -> bool {
439        &self.0 == &other.0
440    }
441}
442
443#[doc(hidden)]
444#[macro_export]
445#[unstable(feature = "bstr_internals", issue = "none")]
446macro_rules! impl_partial_eq {
447    ($lhs:ty, $rhs:ty) => {
448        #[allow(unused_lifetimes)]
449        impl<'a> PartialEq<$rhs> for $lhs {
450            #[inline]
451            fn eq(&self, other: &$rhs) -> bool {
452                let other: &[u8] = other.as_ref();
453                PartialEq::eq(self.as_bytes(), other)
454            }
455        }
456
457        #[allow(unused_lifetimes)]
458        impl<'a> PartialEq<$lhs> for $rhs {
459            #[inline]
460            fn eq(&self, other: &$lhs) -> bool {
461                let this: &[u8] = self.as_ref();
462                PartialEq::eq(this, other.as_bytes())
463            }
464        }
465    };
466}
467
468#[doc(hidden)]
469#[unstable(feature = "bstr_internals", issue = "none")]
470pub use impl_partial_eq;
471
472#[doc(hidden)]
473#[macro_export]
474#[unstable(feature = "bstr_internals", issue = "none")]
475macro_rules! impl_partial_eq_ord {
476    ($lhs:ty, $rhs:ty) => {
477        $crate::bstr::impl_partial_eq!($lhs, $rhs);
478
479        #[allow(unused_lifetimes)]
480        #[unstable(feature = "bstr", issue = "134915")]
481        impl<'a> PartialOrd<$rhs> for $lhs {
482            #[inline]
483            fn partial_cmp(&self, other: &$rhs) -> Option<Ordering> {
484                let other: &[u8] = other.as_ref();
485                PartialOrd::partial_cmp(self.as_bytes(), other)
486            }
487        }
488
489        #[allow(unused_lifetimes)]
490        #[unstable(feature = "bstr", issue = "134915")]
491        impl<'a> PartialOrd<$lhs> for $rhs {
492            #[inline]
493            fn partial_cmp(&self, other: &$lhs) -> Option<Ordering> {
494                let this: &[u8] = self.as_ref();
495                PartialOrd::partial_cmp(this, other.as_bytes())
496            }
497        }
498    };
499}
500
501#[doc(hidden)]
502#[unstable(feature = "bstr_internals", issue = "none")]
503pub use impl_partial_eq_ord;
504
505#[doc(hidden)]
506#[macro_export]
507#[unstable(feature = "bstr_internals", issue = "none")]
508macro_rules! impl_partial_eq_n {
509    ($lhs:ty, $rhs:ty) => {
510        #[allow(unused_lifetimes)]
511        #[unstable(feature = "bstr", issue = "134915")]
512        impl<const N: usize> PartialEq<$rhs> for $lhs {
513            #[inline]
514            fn eq(&self, other: &$rhs) -> bool {
515                let other: &[u8] = other.as_ref();
516                PartialEq::eq(self.as_bytes(), other)
517            }
518        }
519
520        #[allow(unused_lifetimes)]
521        #[unstable(feature = "bstr", issue = "134915")]
522        impl<const N: usize> PartialEq<$lhs> for $rhs {
523            #[inline]
524            fn eq(&self, other: &$lhs) -> bool {
525                let this: &[u8] = self.as_ref();
526                PartialEq::eq(this, other.as_bytes())
527            }
528        }
529    };
530}
531
532#[doc(hidden)]
533#[unstable(feature = "bstr_internals", issue = "none")]
534pub use impl_partial_eq_n;
535
536// PartialOrd with `[u8]` omitted to avoid inference failures
537impl_partial_eq!(ByteStr, [u8]);
538// PartialOrd with `&[u8]` omitted to avoid inference failures
539impl_partial_eq!(ByteStr, &[u8]);
540// PartialOrd with `str` omitted to avoid inference failures
541impl_partial_eq!(ByteStr, str);
542// PartialOrd with `&str` omitted to avoid inference failures
543impl_partial_eq!(ByteStr, &str);
544// PartialOrd with `[u8; N]` omitted to avoid inference failures
545impl_partial_eq_n!(ByteStr, [u8; N]);
546// PartialOrd with `[u8; N]` omitted to avoid inference failures
547impl_partial_eq_n!(ByteStr, &[u8; N]);
548
549#[unstable(feature = "bstr", issue = "134915")]
550impl Ord for ByteStr {
551    #[inline]
552    fn cmp(&self, other: &ByteStr) -> Ordering {
553        Ord::cmp(&self.0, &other.0)
554    }
555}
556
557#[unstable(feature = "bstr", issue = "134915")]
558impl PartialOrd for ByteStr {
559    #[inline]
560    fn partial_cmp(&self, other: &ByteStr) -> Option<Ordering> {
561        PartialOrd::partial_cmp(&self.0, &other.0)
562    }
563}
564
565#[unstable(feature = "bstr", issue = "134915")]
566impl<'a> TryFrom<&'a ByteStr> for &'a str {
567    type Error = crate::str::Utf8Error;
568
569    #[inline]
570    fn try_from(s: &'a ByteStr) -> Result<Self, Self::Error> {
571        crate::str::from_utf8(&s.0)
572    }
573}
574
575#[unstable(feature = "bstr", issue = "134915")]
576impl<'a> TryFrom<&'a mut ByteStr> for &'a mut str {
577    type Error = crate::str::Utf8Error;
578
579    #[inline]
580    fn try_from(s: &'a mut ByteStr) -> Result<Self, Self::Error> {
581        crate::str::from_utf8_mut(&mut s.0)
582    }
583}