winnow/stream/
bytes.rs

1use core::num::NonZeroUsize;
2
3use crate::error::Needed;
4use crate::lib::std::iter::{Cloned, Enumerate};
5use crate::lib::std::slice::Iter;
6use crate::lib::std::{cmp::Ordering, fmt, ops};
7use crate::stream::AsBytes;
8use crate::stream::Checkpoint;
9use crate::stream::Compare;
10use crate::stream::CompareResult;
11use crate::stream::FindSlice;
12use crate::stream::Offset;
13#[cfg(feature = "unstable-recover")]
14#[cfg(feature = "std")]
15use crate::stream::Recover;
16use crate::stream::SliceLen;
17use crate::stream::Stream;
18use crate::stream::StreamIsPartial;
19use crate::stream::UpdateSlice;
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 { crate::lib::std::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    #[inline(always)]
146    fn raw(&self) -> &dyn crate::lib::std::fmt::Debug {
147        self
148    }
149}
150
151#[cfg(feature = "unstable-recover")]
152#[cfg(feature = "std")]
153impl<E> Recover<E> for &Bytes {
154    #[inline(always)]
155    fn record_err(
156        &mut self,
157        _token_start: &Self::Checkpoint,
158        _err_start: &Self::Checkpoint,
159        err: E,
160    ) -> Result<(), E> {
161        Err(err)
162    }
163
164    /// Report whether the [`Stream`] can save off errors for recovery
165    #[inline(always)]
166    fn is_recovery_supported() -> bool {
167        false
168    }
169}
170
171impl StreamIsPartial for &Bytes {
172    type PartialState = ();
173
174    #[inline]
175    fn complete(&mut self) -> Self::PartialState {
176        // Already complete
177    }
178
179    #[inline]
180    fn restore_partial(&mut self, _state: Self::PartialState) {}
181
182    #[inline(always)]
183    fn is_partial_supported() -> bool {
184        false
185    }
186}
187
188impl Offset for &Bytes {
189    #[inline(always)]
190    fn offset_from(&self, start: &Self) -> usize {
191        self.as_bytes().offset_from(&start.as_bytes())
192    }
193}
194
195impl<'a> Offset<<&'a Bytes as Stream>::Checkpoint> for &'a Bytes {
196    #[inline(always)]
197    fn offset_from(&self, other: &<&'a Bytes as Stream>::Checkpoint) -> usize {
198        self.checkpoint().offset_from(other)
199    }
200}
201
202impl AsBytes for &Bytes {
203    #[inline(always)]
204    fn as_bytes(&self) -> &[u8] {
205        (*self).as_bytes()
206    }
207}
208
209impl<'a, T> Compare<T> for &'a Bytes
210where
211    &'a [u8]: Compare<T>,
212{
213    #[inline(always)]
214    fn compare(&self, t: T) -> CompareResult {
215        let bytes = (*self).as_bytes();
216        bytes.compare(t)
217    }
218}
219
220impl<'i, S> FindSlice<S> for &'i Bytes
221where
222    &'i [u8]: FindSlice<S>,
223{
224    #[inline(always)]
225    fn find_slice(&self, substr: S) -> Option<crate::lib::std::ops::Range<usize>> {
226        let bytes = (*self).as_bytes();
227        let offset = bytes.find_slice(substr);
228        offset
229    }
230}
231
232impl UpdateSlice for &Bytes {
233    #[inline(always)]
234    fn update_slice(self, inner: Self::Slice) -> Self {
235        Bytes::new(inner)
236    }
237}
238
239impl fmt::Display for Bytes {
240    #[inline]
241    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
242        <Self as fmt::UpperHex>::fmt(self, f)
243    }
244}
245
246impl fmt::Debug for Bytes {
247    #[inline]
248    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
249        <Self as fmt::UpperHex>::fmt(self, f)
250    }
251}
252
253impl fmt::LowerHex for Bytes {
254    #[inline]
255    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
256        for byte in self.as_bytes() {
257            write!(f, "{byte:0>2x}")?;
258        }
259        Ok(())
260    }
261}
262
263impl fmt::UpperHex for Bytes {
264    #[inline]
265    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
266        for (i, byte) in self.as_bytes().iter().enumerate() {
267            if 0 < i {
268                let absolute = (self.as_bytes().as_ptr() as usize) + i;
269                if f.alternate() && absolute != 0 && absolute % 4 == 0 {
270                    write!(f, "_")?;
271                }
272            }
273            write!(f, "{byte:0>2X}")?;
274        }
275        Ok(())
276    }
277}
278
279impl ops::Deref for Bytes {
280    type Target = [u8];
281
282    #[inline]
283    fn deref(&self) -> &[u8] {
284        self.as_bytes()
285    }
286}
287
288impl ops::Index<usize> for Bytes {
289    type Output = u8;
290
291    #[inline]
292    fn index(&self, idx: usize) -> &u8 {
293        &self.as_bytes()[idx]
294    }
295}
296
297impl ops::Index<ops::RangeFull> for Bytes {
298    type Output = Bytes;
299
300    #[inline]
301    fn index(&self, _: ops::RangeFull) -> &Bytes {
302        self
303    }
304}
305
306impl ops::Index<ops::Range<usize>> for Bytes {
307    type Output = Bytes;
308
309    #[inline]
310    fn index(&self, r: ops::Range<usize>) -> &Bytes {
311        Bytes::new(&self.as_bytes()[r.start..r.end])
312    }
313}
314
315impl ops::Index<ops::RangeInclusive<usize>> for Bytes {
316    type Output = Bytes;
317
318    #[inline]
319    fn index(&self, r: ops::RangeInclusive<usize>) -> &Bytes {
320        Bytes::new(&self.as_bytes()[*r.start()..=*r.end()])
321    }
322}
323
324impl ops::Index<ops::RangeFrom<usize>> for Bytes {
325    type Output = Bytes;
326
327    #[inline]
328    fn index(&self, r: ops::RangeFrom<usize>) -> &Bytes {
329        Bytes::new(&self.as_bytes()[r.start..])
330    }
331}
332
333impl ops::Index<ops::RangeTo<usize>> for Bytes {
334    type Output = Bytes;
335
336    #[inline]
337    fn index(&self, r: ops::RangeTo<usize>) -> &Bytes {
338        Bytes::new(&self.as_bytes()[..r.end])
339    }
340}
341
342impl ops::Index<ops::RangeToInclusive<usize>> for Bytes {
343    type Output = Bytes;
344
345    #[inline]
346    fn index(&self, r: ops::RangeToInclusive<usize>) -> &Bytes {
347        Bytes::new(&self.as_bytes()[..=r.end])
348    }
349}
350
351impl AsRef<[u8]> for Bytes {
352    #[inline]
353    fn as_ref(&self) -> &[u8] {
354        self.as_bytes()
355    }
356}
357
358impl AsRef<Bytes> for [u8] {
359    #[inline]
360    fn as_ref(&self) -> &Bytes {
361        Bytes::new(self)
362    }
363}
364
365impl AsRef<Bytes> for str {
366    #[inline]
367    fn as_ref(&self) -> &Bytes {
368        Bytes::new(self)
369    }
370}
371
372#[cfg(feature = "alloc")]
373impl crate::lib::std::borrow::ToOwned for Bytes {
374    type Owned = crate::lib::std::vec::Vec<u8>;
375
376    #[inline]
377    fn to_owned(&self) -> Self::Owned {
378        crate::lib::std::vec::Vec::from(self.as_bytes())
379    }
380}
381
382#[cfg(feature = "alloc")]
383impl crate::lib::std::borrow::Borrow<Bytes> for crate::lib::std::vec::Vec<u8> {
384    #[inline]
385    fn borrow(&self) -> &Bytes {
386        Bytes::from_bytes(self.as_slice())
387    }
388}
389
390impl<'a> Default for &'a Bytes {
391    fn default() -> &'a Bytes {
392        Bytes::new(b"")
393    }
394}
395
396impl<'a> From<&'a [u8]> for &'a Bytes {
397    #[inline]
398    fn from(s: &'a [u8]) -> &'a Bytes {
399        Bytes::new(s)
400    }
401}
402
403impl<'a> From<&'a Bytes> for &'a [u8] {
404    #[inline]
405    fn from(s: &'a Bytes) -> &'a [u8] {
406        Bytes::as_bytes(s)
407    }
408}
409
410impl<'a> From<&'a str> for &'a Bytes {
411    #[inline]
412    fn from(s: &'a str) -> &'a Bytes {
413        Bytes::new(s.as_bytes())
414    }
415}
416
417impl Eq for Bytes {}
418
419impl PartialEq<Bytes> for Bytes {
420    #[inline]
421    fn eq(&self, other: &Bytes) -> bool {
422        self.as_bytes() == other.as_bytes()
423    }
424}
425
426impl_partial_eq!(Bytes, [u8]);
427impl_partial_eq!(Bytes, &'a [u8]);
428impl_partial_eq!(Bytes, str);
429impl_partial_eq!(Bytes, &'a str);
430
431impl PartialOrd for Bytes {
432    #[inline]
433    fn partial_cmp(&self, other: &Bytes) -> Option<Ordering> {
434        Some(self.cmp(other))
435    }
436}
437
438impl Ord for Bytes {
439    #[inline]
440    fn cmp(&self, other: &Bytes) -> Ordering {
441        Ord::cmp(self.as_bytes(), other.as_bytes())
442    }
443}
444
445impl_partial_ord!(Bytes, [u8]);
446impl_partial_ord!(Bytes, &'a [u8]);
447impl_partial_ord!(Bytes, str);
448impl_partial_ord!(Bytes, &'a str);
449
450#[cfg(all(test, feature = "std"))]
451mod display {
452    use crate::stream::Bytes;
453
454    #[test]
455    fn clean() {
456        assert_eq!(&format!("{}", Bytes::new(b"abc")), "616263");
457        assert_eq!(&format!("{}", Bytes::new(b"\xf0\x28\x8c\xbc")), "F0288CBC");
458    }
459}
460
461#[cfg(all(test, feature = "std"))]
462mod debug {
463    use crate::stream::Bytes;
464
465    #[test]
466    fn test_debug() {
467        assert_eq!(
468            "000000206674797069736F6D0000020069736F6D69736F32617663316D70",
469            format!(
470                "{:?}",
471                Bytes::new(b"\0\0\0 ftypisom\0\0\x02\0isomiso2avc1mp")
472            ),
473        );
474    }
475
476    #[test]
477    fn test_pretty_debug() {
478        // Output can change from run-to-run
479        let _ = format!(
480            "{:#?}",
481            Bytes::new(b"\0\0\0 ftypisom\0\0\x02\0isomiso2avc1mp")
482        );
483    }
484
485    #[test]
486    fn test_sliced() {
487        // Output can change from run-to-run
488        let total = Bytes::new(b"12345678901234567890");
489        let _ = format!("{total:#?}");
490        let _ = format!("{:#?}", &total[1..]);
491        let _ = format!("{:#?}", &total[10..]);
492    }
493}