1use core::num::NonZeroUsize;
2
3use crate::stream::AsBytes;
4use crate::stream::Checkpoint;
5use crate::stream::Compare;
6use crate::stream::CompareResult;
7use crate::stream::FindSlice;
8use crate::stream::Needed;
9use crate::stream::Offset;
10#[cfg(feature = "unstable-recover")]
11#[cfg(feature = "std")]
12use crate::stream::Recover;
13use crate::stream::SliceLen;
14use crate::stream::Stream;
15use crate::stream::StreamIsPartial;
16use crate::stream::UpdateSlice;
17use core::iter::{Cloned, Enumerate};
18use core::slice::Iter;
19use core::{cmp::Ordering, fmt, ops};
20
21#[allow(clippy::derived_hash_with_manual_eq)]
23#[derive(Hash)]
24#[repr(transparent)]
25pub struct Bytes([u8]);
26
27impl Bytes {
28 #[inline]
30 pub fn new<B: ?Sized + AsRef<[u8]>>(bytes: &B) -> &Self {
31 Self::from_bytes(bytes.as_ref())
32 }
33
34 #[inline]
35 fn from_bytes(slice: &[u8]) -> &Self {
36 unsafe { core::mem::transmute(slice) }
37 }
38
39 #[inline]
40 fn as_bytes(&self) -> &[u8] {
41 &self.0
42 }
43}
44
45impl SliceLen for &Bytes {
46 #[inline(always)]
47 fn slice_len(&self) -> usize {
48 self.len()
49 }
50}
51
52impl<'i> Stream for &'i Bytes {
53 type Token = u8;
54 type Slice = &'i [u8];
55
56 type IterOffsets = Enumerate<Cloned<Iter<'i, u8>>>;
57
58 type Checkpoint = Checkpoint<Self, Self>;
59
60 #[inline(always)]
61 fn iter_offsets(&self) -> Self::IterOffsets {
62 self.iter().cloned().enumerate()
63 }
64 #[inline(always)]
65 fn eof_offset(&self) -> usize {
66 self.len()
67 }
68
69 #[inline(always)]
70 fn next_token(&mut self) -> Option<Self::Token> {
71 if self.is_empty() {
72 None
73 } else {
74 let token = self[0];
75 *self = &self[1..];
76 Some(token)
77 }
78 }
79
80 #[inline(always)]
81 fn peek_token(&self) -> Option<Self::Token> {
82 if self.is_empty() {
83 None
84 } else {
85 Some(self[0])
86 }
87 }
88
89 #[inline(always)]
90 fn offset_for<P>(&self, predicate: P) -> Option<usize>
91 where
92 P: Fn(Self::Token) -> bool,
93 {
94 self.iter().position(|b| predicate(*b))
95 }
96 #[inline(always)]
97 fn offset_at(&self, tokens: usize) -> Result<usize, Needed> {
98 if let Some(needed) = tokens.checked_sub(self.len()).and_then(NonZeroUsize::new) {
99 Err(Needed::Size(needed))
100 } else {
101 Ok(tokens)
102 }
103 }
104 #[inline(always)]
105 fn next_slice(&mut self, offset: usize) -> Self::Slice {
106 let (slice, next) = self.0.split_at(offset);
107 *self = Bytes::from_bytes(next);
108 slice
109 }
110 #[inline(always)]
111 unsafe fn next_slice_unchecked(&mut self, offset: usize) -> Self::Slice {
112 #[cfg(debug_assertions)]
113 self.peek_slice(offset);
114
115 let slice = unsafe { self.0.get_unchecked(..offset) };
117 let next = unsafe { self.0.get_unchecked(offset..) };
119 *self = Bytes::from_bytes(next);
120 slice
121 }
122 #[inline(always)]
123 fn peek_slice(&self, offset: usize) -> Self::Slice {
124 &self[..offset]
125 }
126 #[inline(always)]
127 unsafe fn peek_slice_unchecked(&self, offset: usize) -> Self::Slice {
128 #[cfg(debug_assertions)]
129 self.peek_slice(offset);
130
131 let slice = unsafe { self.0.get_unchecked(..offset) };
133 slice
134 }
135
136 #[inline(always)]
137 fn checkpoint(&self) -> Self::Checkpoint {
138 Checkpoint::<_, Self>::new(*self)
139 }
140 #[inline(always)]
141 fn reset(&mut self, checkpoint: &Self::Checkpoint) {
142 *self = checkpoint.inner;
143 }
144
145 fn trace(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
146 write!(f, "{self:#?}")
147 }
148}
149
150#[cfg(feature = "unstable-recover")]
151#[cfg(feature = "std")]
152impl<E> Recover<E> for &Bytes {
153 #[inline(always)]
154 fn record_err(
155 &mut self,
156 _token_start: &Self::Checkpoint,
157 _err_start: &Self::Checkpoint,
158 err: E,
159 ) -> Result<(), E> {
160 Err(err)
161 }
162
163 #[inline(always)]
165 fn is_recovery_supported() -> bool {
166 false
167 }
168}
169
170impl StreamIsPartial for &Bytes {
171 type PartialState = ();
172
173 #[inline]
174 fn complete(&mut self) -> Self::PartialState {
175 }
177
178 #[inline]
179 fn restore_partial(&mut self, _state: Self::PartialState) {}
180
181 #[inline(always)]
182 fn is_partial_supported() -> bool {
183 false
184 }
185}
186
187impl Offset for &Bytes {
188 #[inline(always)]
189 fn offset_from(&self, start: &Self) -> usize {
190 self.as_bytes().offset_from(&start.as_bytes())
191 }
192}
193
194impl<'a> Offset<<&'a Bytes as Stream>::Checkpoint> for &'a Bytes {
195 #[inline(always)]
196 fn offset_from(&self, other: &<&'a Bytes as Stream>::Checkpoint) -> usize {
197 self.checkpoint().offset_from(other)
198 }
199}
200
201impl AsBytes for &Bytes {
202 #[inline(always)]
203 fn as_bytes(&self) -> &[u8] {
204 (*self).as_bytes()
205 }
206}
207
208impl<'a, T> Compare<T> for &'a Bytes
209where
210 &'a [u8]: Compare<T>,
211{
212 #[inline(always)]
213 fn compare(&self, t: T) -> CompareResult {
214 let bytes = (*self).as_bytes();
215 bytes.compare(t)
216 }
217}
218
219impl<'i, S> FindSlice<S> for &'i Bytes
220where
221 &'i [u8]: FindSlice<S>,
222{
223 #[inline(always)]
224 fn find_slice(&self, substr: S) -> Option<core::ops::Range<usize>> {
225 let bytes = (*self).as_bytes();
226 let offset = bytes.find_slice(substr);
227 offset
228 }
229}
230
231impl UpdateSlice for &Bytes {
232 #[inline(always)]
233 fn update_slice(self, inner: Self::Slice) -> Self {
234 Bytes::new(inner)
235 }
236}
237
238impl fmt::Display for Bytes {
239 #[inline]
240 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
241 <Self as fmt::UpperHex>::fmt(self, f)
242 }
243}
244
245impl fmt::Debug for Bytes {
246 #[inline]
247 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
248 <Self as fmt::UpperHex>::fmt(self, f)
249 }
250}
251
252impl fmt::LowerHex for Bytes {
253 #[inline]
254 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
255 for byte in self.as_bytes() {
256 write!(f, "{byte:0>2x}")?;
257 }
258 Ok(())
259 }
260}
261
262impl fmt::UpperHex for Bytes {
263 #[inline]
264 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
265 for (i, byte) in self.as_bytes().iter().enumerate() {
266 if 0 < i {
267 let absolute = (self.as_bytes().as_ptr() as usize) + i;
268 if f.alternate() && absolute != 0 && absolute % 4 == 0 {
269 write!(f, "_")?;
270 }
271 }
272 write!(f, "{byte:0>2X}")?;
273 }
274 Ok(())
275 }
276}
277
278impl ops::Deref for Bytes {
279 type Target = [u8];
280
281 #[inline]
282 fn deref(&self) -> &[u8] {
283 self.as_bytes()
284 }
285}
286
287impl ops::Index<usize> for Bytes {
288 type Output = u8;
289
290 #[inline]
291 fn index(&self, idx: usize) -> &u8 {
292 &self.as_bytes()[idx]
293 }
294}
295
296impl ops::Index<ops::RangeFull> for Bytes {
297 type Output = Bytes;
298
299 #[inline]
300 fn index(&self, _: ops::RangeFull) -> &Bytes {
301 self
302 }
303}
304
305impl ops::Index<ops::Range<usize>> for Bytes {
306 type Output = Bytes;
307
308 #[inline]
309 fn index(&self, r: ops::Range<usize>) -> &Bytes {
310 Bytes::new(&self.as_bytes()[r.start..r.end])
311 }
312}
313
314impl ops::Index<ops::RangeInclusive<usize>> for Bytes {
315 type Output = Bytes;
316
317 #[inline]
318 fn index(&self, r: ops::RangeInclusive<usize>) -> &Bytes {
319 Bytes::new(&self.as_bytes()[*r.start()..=*r.end()])
320 }
321}
322
323impl ops::Index<ops::RangeFrom<usize>> for Bytes {
324 type Output = Bytes;
325
326 #[inline]
327 fn index(&self, r: ops::RangeFrom<usize>) -> &Bytes {
328 Bytes::new(&self.as_bytes()[r.start..])
329 }
330}
331
332impl ops::Index<ops::RangeTo<usize>> for Bytes {
333 type Output = Bytes;
334
335 #[inline]
336 fn index(&self, r: ops::RangeTo<usize>) -> &Bytes {
337 Bytes::new(&self.as_bytes()[..r.end])
338 }
339}
340
341impl ops::Index<ops::RangeToInclusive<usize>> for Bytes {
342 type Output = Bytes;
343
344 #[inline]
345 fn index(&self, r: ops::RangeToInclusive<usize>) -> &Bytes {
346 Bytes::new(&self.as_bytes()[..=r.end])
347 }
348}
349
350impl AsRef<[u8]> for Bytes {
351 #[inline]
352 fn as_ref(&self) -> &[u8] {
353 self.as_bytes()
354 }
355}
356
357impl AsRef<Bytes> for [u8] {
358 #[inline]
359 fn as_ref(&self) -> &Bytes {
360 Bytes::new(self)
361 }
362}
363
364impl AsRef<Bytes> for str {
365 #[inline]
366 fn as_ref(&self) -> &Bytes {
367 Bytes::new(self)
368 }
369}
370
371#[cfg(feature = "alloc")]
372impl alloc::borrow::ToOwned for Bytes {
373 type Owned = alloc::vec::Vec<u8>;
374
375 #[inline]
376 fn to_owned(&self) -> Self::Owned {
377 alloc::vec::Vec::from(self.as_bytes())
378 }
379}
380
381#[cfg(feature = "alloc")]
382impl core::borrow::Borrow<Bytes> for alloc::vec::Vec<u8> {
383 #[inline]
384 fn borrow(&self) -> &Bytes {
385 Bytes::from_bytes(self.as_slice())
386 }
387}
388
389impl<'a> Default for &'a Bytes {
390 fn default() -> &'a Bytes {
391 Bytes::new(b"")
392 }
393}
394
395impl<'a> From<&'a [u8]> for &'a Bytes {
396 #[inline]
397 fn from(s: &'a [u8]) -> &'a Bytes {
398 Bytes::new(s)
399 }
400}
401
402impl<'a> From<&'a Bytes> for &'a [u8] {
403 #[inline]
404 fn from(s: &'a Bytes) -> &'a [u8] {
405 Bytes::as_bytes(s)
406 }
407}
408
409impl<'a> From<&'a str> for &'a Bytes {
410 #[inline]
411 fn from(s: &'a str) -> &'a Bytes {
412 Bytes::new(s.as_bytes())
413 }
414}
415
416impl Eq for Bytes {}
417
418impl PartialEq<Bytes> for Bytes {
419 #[inline]
420 fn eq(&self, other: &Bytes) -> bool {
421 self.as_bytes() == other.as_bytes()
422 }
423}
424
425impl_partial_eq!(Bytes, [u8]);
426impl_partial_eq!(Bytes, &'a [u8]);
427impl_partial_eq!(Bytes, str);
428impl_partial_eq!(Bytes, &'a str);
429
430impl PartialOrd for Bytes {
431 #[inline]
432 fn partial_cmp(&self, other: &Bytes) -> Option<Ordering> {
433 Some(self.cmp(other))
434 }
435}
436
437impl Ord for Bytes {
438 #[inline]
439 fn cmp(&self, other: &Bytes) -> Ordering {
440 Ord::cmp(self.as_bytes(), other.as_bytes())
441 }
442}
443
444impl_partial_ord!(Bytes, [u8]);
445impl_partial_ord!(Bytes, &'a [u8]);
446impl_partial_ord!(Bytes, str);
447impl_partial_ord!(Bytes, &'a str);
448
449#[cfg(test)]
450mod test {
451 use crate::stream::Bytes;
452
453 #[test]
454 fn partial_eq_bytes_byte_slice() {
455 let input = b"foo".as_slice();
456 let actual = Bytes::new(input);
457 assert!(actual == input);
458 }
459
460 #[test]
461 fn partial_eq_byte_slice_bytes() {
462 let input = b"foo".as_slice();
463 let actual = Bytes::new(input);
464 assert!(input == actual);
465 }
466
467 #[test]
468 fn partial_eq_bytes_str() {
469 let input = "foo";
470 let actual = Bytes::new(input);
471 assert!(actual == input);
472 }
473
474 #[test]
475 fn partial_eq_str_bytes() {
476 let input = "foo";
477 let actual = Bytes::new(input);
478 assert!(input == actual);
479 }
480
481 #[test]
482 fn partial_ord_bytes_byte_slice() {
483 let input = b"foo".as_slice();
484 let actual = Bytes::new(input);
485 assert!(actual.partial_cmp(input) == Some(core::cmp::Ordering::Equal));
486 }
487
488 #[test]
489 fn partial_ord_byte_slice_bytes() {
490 let input = b"foo".as_slice();
491 let actual = Bytes::new(input);
492 assert!(input.partial_cmp(actual) == Some(core::cmp::Ordering::Equal));
493 }
494
495 #[test]
496 fn partial_ord_bytes_str() {
497 let input = "foo";
498 let actual = Bytes::new(input);
499 assert!(actual.partial_cmp(input) == Some(core::cmp::Ordering::Equal));
500 }
501
502 #[test]
503 fn partial_ord_str_bytes() {
504 let input = "foo";
505 let actual = Bytes::new(input);
506 assert!(input.partial_cmp(actual) == Some(core::cmp::Ordering::Equal));
507 }
508}
509
510#[cfg(all(test, feature = "std"))]
511mod display {
512 use crate::stream::Bytes;
513
514 #[test]
515 fn clean() {
516 assert_eq!(&format!("{}", Bytes::new(b"abc")), "616263");
517 assert_eq!(&format!("{}", Bytes::new(b"\xf0\x28\x8c\xbc")), "F0288CBC");
518 }
519}
520
521#[cfg(all(test, feature = "std"))]
522mod debug {
523 use crate::stream::Bytes;
524 use crate::stream::Stream as _;
525 use snapbox::assert_data_eq;
526 use snapbox::str;
527
528 #[test]
529 fn test_debug() {
530 let input = Bytes::new(b"\0\0\0 ftypisom\0\0\x02\0isomiso2avc1mp");
531 let expected = str!["000000206674797069736F6D0000020069736F6D69736F32617663316D70"];
532 assert_data_eq!(&format!("{input:?}"), expected);
533 }
534
535 #[test]
536 fn test_pretty_debug() {
537 let input = Bytes::new(b"\0\0\0 ftypisom\0\0\x02\0isomiso2avc1mp");
538 let expected = str!["000000206674797069736F6D0000020069736F6D69736F32617663316D70"];
539 assert_data_eq!(&format!("{input:#?}").replace('_', ""), expected);
540 }
541
542 #[test]
543 fn test_trace() {
544 let input = Bytes::new(b"\0\0\0 ftypisom\0\0\x02\0isomiso2avc1mp");
545 let expected = str!["000000206674797069736F6D0000020069736F6D69736F32617663316D70"];
546 assert_data_eq!(
547 crate::util::from_fn(|f| input.trace(f))
548 .to_string()
549 .replace('_', ""),
550 expected
551 );
552 }
553
554 #[test]
555 fn test_sliced() {
556 let total = Bytes::new(b"12345678901234567890");
558 let _ = format!("{total:#?}");
559 let _ = format!("{:#?}", &total[1..]);
560 let _ = format!("{:#?}", &total[10..]);
561 }
562}