1 | //! The `ByteStr` type and trait implementations. |
2 | |
3 | mod traits; |
4 | |
5 | #[unstable (feature = "bstr_internals" , issue = "none" )] |
6 | pub use traits::{impl_partial_eq, impl_partial_eq_n, impl_partial_eq_ord}; |
7 | |
8 | use crate::borrow::{Borrow, BorrowMut}; |
9 | use crate::fmt; |
10 | use 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" )] |
43 | pub struct ByteStr(pub [u8]); |
44 | |
45 | impl 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 | #[doc (hidden)] |
96 | #[unstable (feature = "bstr_internals" , issue = "none" )] |
97 | #[inline ] |
98 | pub fn as_bytes_mut(&mut self) -> &mut [u8] { |
99 | &mut self.0 |
100 | } |
101 | } |
102 | |
103 | #[unstable (feature = "bstr" , issue = "134915" )] |
104 | impl Deref for ByteStr { |
105 | type Target = [u8]; |
106 | |
107 | #[inline ] |
108 | fn deref(&self) -> &[u8] { |
109 | &self.0 |
110 | } |
111 | } |
112 | |
113 | #[unstable (feature = "bstr" , issue = "134915" )] |
114 | impl DerefMut for ByteStr { |
115 | #[inline ] |
116 | fn deref_mut(&mut self) -> &mut [u8] { |
117 | &mut self.0 |
118 | } |
119 | } |
120 | |
121 | #[unstable (feature = "deref_pure_trait" , issue = "87121" )] |
122 | unsafe impl DerefPure for ByteStr {} |
123 | |
124 | #[unstable (feature = "bstr" , issue = "134915" )] |
125 | impl fmt::Debug for ByteStr { |
126 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
127 | write!(f, " \"" )?; |
128 | for chunk: Utf8Chunk<'_> in self.utf8_chunks() { |
129 | for c: char in chunk.valid().chars() { |
130 | match c { |
131 | ' \0' => write!(f, " \\0" )?, |
132 | ' \x01' ..=' \x7f' => write!(f, " {}" , (c as u8).escape_ascii())?, |
133 | _ => write!(f, " {}" , c.escape_debug())?, |
134 | } |
135 | } |
136 | write!(f, " {}" , chunk.invalid().escape_ascii())?; |
137 | } |
138 | write!(f, " \"" )?; |
139 | Ok(()) |
140 | } |
141 | } |
142 | |
143 | #[unstable (feature = "bstr" , issue = "134915" )] |
144 | impl fmt::Display for ByteStr { |
145 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
146 | fn fmt_nopad(this: &ByteStr, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
147 | for chunk in this.utf8_chunks() { |
148 | f.write_str(chunk.valid())?; |
149 | if !chunk.invalid().is_empty() { |
150 | f.write_str(" \u{FFFD}" )?; |
151 | } |
152 | } |
153 | Ok(()) |
154 | } |
155 | |
156 | let Some(align) = f.align() else { |
157 | return fmt_nopad(self, f); |
158 | }; |
159 | let nchars: usize = self |
160 | .utf8_chunks() |
161 | .map(|chunk| { |
162 | chunk.valid().chars().count() + if chunk.invalid().is_empty() { 0 } else { 1 } |
163 | }) |
164 | .sum(); |
165 | let padding = f.width().unwrap_or(0).saturating_sub(nchars); |
166 | let fill = f.fill(); |
167 | let (lpad, rpad) = match align { |
168 | fmt::Alignment::Left => (0, padding), |
169 | fmt::Alignment::Right => (padding, 0), |
170 | fmt::Alignment::Center => { |
171 | let half = padding / 2; |
172 | (half, half + padding % 2) |
173 | } |
174 | }; |
175 | for _ in 0..lpad { |
176 | write!(f, " {fill}" )?; |
177 | } |
178 | fmt_nopad(self, f)?; |
179 | for _ in 0..rpad { |
180 | write!(f, " {fill}" )?; |
181 | } |
182 | |
183 | Ok(()) |
184 | } |
185 | } |
186 | |
187 | #[unstable (feature = "bstr" , issue = "134915" )] |
188 | impl AsRef<[u8]> for ByteStr { |
189 | #[inline ] |
190 | fn as_ref(&self) -> &[u8] { |
191 | &self.0 |
192 | } |
193 | } |
194 | |
195 | #[unstable (feature = "bstr" , issue = "134915" )] |
196 | impl AsRef<ByteStr> for ByteStr { |
197 | #[inline ] |
198 | fn as_ref(&self) -> &ByteStr { |
199 | self |
200 | } |
201 | } |
202 | |
203 | // `impl AsRef<ByteStr> for [u8]` omitted to avoid widespread inference failures |
204 | |
205 | #[unstable (feature = "bstr" , issue = "134915" )] |
206 | impl AsRef<ByteStr> for str { |
207 | #[inline ] |
208 | fn as_ref(&self) -> &ByteStr { |
209 | ByteStr::new(self) |
210 | } |
211 | } |
212 | |
213 | #[unstable (feature = "bstr" , issue = "134915" )] |
214 | impl AsMut<[u8]> for ByteStr { |
215 | #[inline ] |
216 | fn as_mut(&mut self) -> &mut [u8] { |
217 | &mut self.0 |
218 | } |
219 | } |
220 | |
221 | // `impl AsMut<ByteStr> for [u8]` omitted to avoid widespread inference failures |
222 | |
223 | // `impl Borrow<ByteStr> for [u8]` omitted to avoid widespread inference failures |
224 | |
225 | // `impl Borrow<ByteStr> for str` omitted to avoid widespread inference failures |
226 | |
227 | #[unstable (feature = "bstr" , issue = "134915" )] |
228 | impl Borrow<[u8]> for ByteStr { |
229 | #[inline ] |
230 | fn borrow(&self) -> &[u8] { |
231 | &self.0 |
232 | } |
233 | } |
234 | |
235 | // `impl BorrowMut<ByteStr> for [u8]` omitted to avoid widespread inference failures |
236 | |
237 | #[unstable (feature = "bstr" , issue = "134915" )] |
238 | impl BorrowMut<[u8]> for ByteStr { |
239 | #[inline ] |
240 | fn borrow_mut(&mut self) -> &mut [u8] { |
241 | &mut self.0 |
242 | } |
243 | } |
244 | |
245 | #[unstable (feature = "bstr" , issue = "134915" )] |
246 | impl<'a> Default for &'a ByteStr { |
247 | fn default() -> Self { |
248 | ByteStr::from_bytes(slice:b"" ) |
249 | } |
250 | } |
251 | |
252 | #[unstable (feature = "bstr" , issue = "134915" )] |
253 | impl<'a> Default for &'a mut ByteStr { |
254 | fn default() -> Self { |
255 | ByteStr::from_bytes_mut(&mut []) |
256 | } |
257 | } |
258 | |
259 | // Omitted due to inference failures |
260 | // |
261 | // #[unstable(feature = "bstr", issue = "134915")] |
262 | // impl<'a, const N: usize> From<&'a [u8; N]> for &'a ByteStr { |
263 | // #[inline] |
264 | // fn from(s: &'a [u8; N]) -> Self { |
265 | // ByteStr::from_bytes(s) |
266 | // } |
267 | // } |
268 | // |
269 | // #[unstable(feature = "bstr", issue = "134915")] |
270 | // impl<'a> From<&'a [u8]> for &'a ByteStr { |
271 | // #[inline] |
272 | // fn from(s: &'a [u8]) -> Self { |
273 | // ByteStr::from_bytes(s) |
274 | // } |
275 | // } |
276 | |
277 | // Omitted due to slice-from-array-issue-113238: |
278 | // |
279 | // #[unstable(feature = "bstr", issue = "134915")] |
280 | // impl<'a> From<&'a ByteStr> for &'a [u8] { |
281 | // #[inline] |
282 | // fn from(s: &'a ByteStr) -> Self { |
283 | // &s.0 |
284 | // } |
285 | // } |
286 | // |
287 | // #[unstable(feature = "bstr", issue = "134915")] |
288 | // impl<'a> From<&'a mut ByteStr> for &'a mut [u8] { |
289 | // #[inline] |
290 | // fn from(s: &'a mut ByteStr) -> Self { |
291 | // &mut s.0 |
292 | // } |
293 | // } |
294 | |
295 | // Omitted due to inference failures |
296 | // |
297 | // #[unstable(feature = "bstr", issue = "134915")] |
298 | // impl<'a> From<&'a str> for &'a ByteStr { |
299 | // #[inline] |
300 | // fn from(s: &'a str) -> Self { |
301 | // ByteStr::from_bytes(s.as_bytes()) |
302 | // } |
303 | // } |
304 | |
305 | #[unstable (feature = "bstr" , issue = "134915" )] |
306 | impl<'a> TryFrom<&'a ByteStr> for &'a str { |
307 | type Error = crate::str::Utf8Error; |
308 | |
309 | #[inline ] |
310 | fn try_from(s: &'a ByteStr) -> Result<Self, Self::Error> { |
311 | crate::str::from_utf8(&s.0) |
312 | } |
313 | } |
314 | |
315 | #[unstable (feature = "bstr" , issue = "134915" )] |
316 | impl<'a> TryFrom<&'a mut ByteStr> for &'a mut str { |
317 | type Error = crate::str::Utf8Error; |
318 | |
319 | #[inline ] |
320 | fn try_from(s: &'a mut ByteStr) -> Result<Self, Self::Error> { |
321 | crate::str::from_utf8_mut(&mut s.0) |
322 | } |
323 | } |
324 | |