Skip to main content

winnow/stream/
bytes.rs

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/// Improved `Debug` experience for `&[u8]` byte streams
22#[allow(clippy::derived_hash_with_manual_eq)]
23#[derive(Hash)]
24#[repr(transparent)]
25pub struct Bytes([u8]);
26
27impl Bytes {
28    /// Make a stream out of a byte slice-like.
29    #[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        // SAFETY: `Stream::next_slice_unchecked` requires `offset` to be in bounds
116        let slice = unsafe { self.0.get_unchecked(..offset) };
117        // SAFETY: `Stream::next_slice_unchecked` requires `offset` to be in bounds
118        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        // SAFETY: `Stream::next_slice_unchecked` requires `offset` to be in bounds
132        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    /// Report whether the [`Stream`] can save off errors for recovery
164    #[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        // Already complete
176    }
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        // Output can change from run-to-run
557        let total = Bytes::new(b"12345678901234567890");
558        let _ = format!("{total:#?}");
559        let _ = format!("{:#?}", &total[1..]);
560        let _ = format!("{:#?}", &total[10..]);
561    }
562}