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