1use 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#[unstable(feature = "bstr", issue = "134915")]
41#[repr(transparent)]
42#[doc(alias = "BStr")]
43pub struct ByteStr(pub [u8]);
44
45impl ByteStr {
46 #[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 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 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#[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#[unstable(feature = "bstr", issue = "134915")]
219impl Borrow<[u8]> for ByteStr {
220 #[inline]
221 fn borrow(&self) -> &[u8] {
222 &self.0
223 }
224}
225
226#[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#[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
534impl_partial_eq!(ByteStr, [u8]);
536impl_partial_eq!(ByteStr, &[u8]);
538impl_partial_eq!(ByteStr, str);
540impl_partial_eq!(ByteStr, &str);
542impl_partial_eq_n!(ByteStr, [u8; N]);
544impl_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}