Skip to main content

parsio/
read.rs

1use std::borrow::Cow;
2
3use crate::error::{ReadError, ReadResult};
4
5pub trait Read<'data> {
6    /// Peek a single byte over the data stream, without advancing it.
7    fn peek_byte(&mut self) -> ReadResult<u8>;
8    /// Manually advances the data stream by `n` bytes. Usually used in tandem with [`Self::peek_byte`]
9    fn advance(&mut self, n: usize) -> ReadResult<()>;
10    /// Read a single byte from the data stream
11    fn read_byte(&mut self) -> ReadResult<u8>;
12    /// Read a byte slice from the data stream of length `len`
13    /// Errors out if `n` is bigger than the remaining data stream
14    fn read_slice(&mut self, len: usize) -> ReadResult<Cow<'data, [u8]>>;
15    /// Read a byte array from the data stream of len `N`
16    /// Basically behaves the same as [`Self::read_slice`] but with a sized slice
17    fn read_array<const N: usize>(&mut self) -> ReadResult<Cow<'data, [u8; N]>>;
18    /// Reads the data stream till EOF
19    fn read_till_eof(&mut self) -> ReadResult<Cow<'data, [u8]>>;
20}
21
22#[derive(Debug)]
23/// Depth-aware wrapper around a [`Read`] implementation.
24/// If you care about billion-laughs attacks, then you should use it.
25pub struct DepthAwareReader<'data, R: Read<'data>> {
26    reader: R,
27    limit: usize,
28    depth: usize,
29    _marker: std::marker::PhantomData<&'data ()>,
30}
31
32impl<'data, R: Read<'data>> DepthAwareReader<'data, R> {
33    /// Default depth limit
34    pub const DEFAULT_LIMIT: usize = 256;
35
36    /// Initializes a DepthAwareReader using [`Self::DEFAULT_LIMIT`] as a depth limit
37    #[inline(always)]
38    pub fn from_reader(reader: R) -> Self {
39        Self {
40            reader,
41            limit: Self::DEFAULT_LIMIT,
42            depth: 0,
43            _marker: Default::default(),
44        }
45    }
46
47    /// Initializes a DepthAwareReader using a custom depth limit
48    #[inline(always)]
49    pub fn from_reader_with_limit(reader: R, limit: usize) -> Self {
50        Self {
51            reader,
52            limit,
53            depth: 0,
54            _marker: Default::default(),
55        }
56    }
57
58    /// Increments the current depth, checks if it didn't exceed the limit and
59    /// returns a Guard that exits this depth when dropped
60    #[inline(always)]
61    pub fn enter(&mut self) -> ReadResult<DepthAwareReaderGuard<'_, 'data, R>> {
62        self.depth += 1;
63        if self.depth <= self.limit {
64            Ok(DepthAwareReaderGuard::new(self))
65        } else {
66            Err(ReadError::AllowedDepthOverflow {
67                depth: self.depth,
68                limit: self.limit,
69            })
70        }
71    }
72}
73
74/// Guard that decredements the current depth when dropped
75pub struct DepthAwareReaderGuard<'a, 'data, R: Read<'data>> {
76    reader: &'a mut DepthAwareReader<'data, R>,
77    accumulated_depth: usize,
78}
79
80impl<'a, 'data, R: Read<'data>> DepthAwareReaderGuard<'a, 'data, R> {
81    #[inline]
82    fn new(rdr: &'a mut DepthAwareReader<'data, R>) -> Self {
83        Self {
84            reader: rdr,
85            accumulated_depth: 1,
86        }
87    }
88
89    #[inline]
90    pub fn enter(mut self) -> ReadResult<Self> {
91        self.reader.depth += 1;
92        self.accumulated_depth += 1;
93        if self.reader.depth <= self.reader.limit {
94            Ok(self)
95        } else {
96            Err(ReadError::AllowedDepthOverflow {
97                depth: self.reader.depth,
98                limit: self.reader.limit,
99            })
100        }
101    }
102}
103
104impl<'a, 'data, R: Read<'data>> Drop for DepthAwareReaderGuard<'a, 'data, R> {
105    #[inline(always)]
106    fn drop(&mut self) {
107        self.reader.depth -= self.accumulated_depth;
108    }
109}
110
111/// Delegate reader impl
112impl<'data, R: Read<'data>> Read<'data> for DepthAwareReader<'data, R> {
113    #[inline(always)]
114    fn peek_byte(&mut self) -> ReadResult<u8> {
115        self.reader.peek_byte()
116    }
117
118    #[inline(always)]
119    fn advance(&mut self, n: usize) -> ReadResult<()> {
120        self.reader.advance(n)
121    }
122
123    #[inline(always)]
124    fn read_byte(&mut self) -> ReadResult<u8> {
125        self.reader.read_byte()
126    }
127
128    #[inline(always)]
129    fn read_slice<'a>(&'a mut self, len: usize) -> ReadResult<Cow<'data, [u8]>> {
130        self.reader.read_slice(len)
131    }
132
133    #[inline(always)]
134    fn read_array<const N: usize>(&mut self) -> ReadResult<Cow<'data, [u8; N]>> {
135        self.reader.read_array()
136    }
137
138    #[inline(always)]
139    fn read_till_eof(&mut self) -> ReadResult<Cow<'data, [u8]>> {
140        self.reader.read_till_eof()
141    }
142}
143
144/// Implementation on base slices. This is what you'd want to use when having something that can hold
145/// in-memory or when memory-mapping large-ish files
146///
147/// ## Attention
148/// - Careful, Windows isn't very happy with 4GB memory-maps because 32-bit mmap is so 1980.
149impl<'data> Read<'data> for &'data [u8] {
150    #[inline]
151    fn peek_byte(&mut self) -> ReadResult<u8> {
152        if self.is_empty() {
153            return Err(ReadError::IoError(std::io::ErrorKind::UnexpectedEof));
154        }
155        // SAFETY: The precondition above satisfies invariants
156        Ok(unsafe { *self.as_ptr() })
157    }
158
159    #[inline]
160    fn advance(&mut self, n: usize) -> ReadResult<()> {
161        if n > self.len() {
162            return Err(ReadError::IoError(std::io::ErrorKind::UnexpectedEof));
163        }
164
165        // SAFETY: The check above fulfill the invariants required by this function
166        *self = unsafe { std::slice::from_raw_parts(self.as_ptr().add(n), self.len() - n) };
167        Ok(())
168    }
169
170    #[inline]
171    fn read_byte(&mut self) -> ReadResult<u8> {
172        if self.is_empty() {
173            return Err(ReadError::IoError(std::io::ErrorKind::UnexpectedEof));
174        }
175        let ptr = self.as_ptr();
176        // SAFETY: The precondition above satisfies invariants of dereferencing the buffer pointer
177        // (it dereferences to the first element of the slice, which is a byte)
178        let b = unsafe { *ptr };
179        // SAFETY: The above call will error out if the preconditions for from_raw_parts wouldn't be fulfilled
180        *self = unsafe { std::slice::from_raw_parts(ptr.add(1), self.len() - 1) };
181        Ok(b)
182    }
183
184    #[inline]
185    fn read_slice<'a>(&'a mut self, len: usize) -> ReadResult<Cow<'data, [u8]>> {
186        let Some((start, end)) = self.split_at_checked(len) else {
187            return Err(ReadError::IoError(std::io::ErrorKind::UnexpectedEof));
188        };
189
190        *self = end;
191        Ok(Cow::Borrowed(start))
192    }
193
194    #[inline]
195    fn read_array<const N: usize>(&mut self) -> ReadResult<Cow<'data, [u8; N]>> {
196        let Some((start, end)) = self.split_at_checked(N) else {
197            return Err(ReadError::IoError(std::io::ErrorKind::UnexpectedEof));
198        };
199
200        *self = end;
201        // SAFETY: The `start` slice will always be exactly N elements long, so this is safe.
202        // Anyway this is basically what `slice::as_array` is, but without the length checks
203        // as they are done above in `split_at_checked`.
204        //
205        // From std:
206        // > SAFETY: The underlying array of a slice can be reinterpreted as an actual
207        // > array `[T; N]` if `N` is not greater than the slice's length.
208        Ok(Cow::Borrowed(unsafe { &*start.as_ptr().cast() }))
209    }
210
211    #[inline]
212    fn read_till_eof(&mut self) -> ReadResult<Cow<'data, [u8]>> {
213        self.read_slice(self.len())
214    }
215}
216
217impl<'data> Read<'data> for Vec<u8> {
218    #[inline(always)]
219    fn peek_byte(&mut self) -> ReadResult<u8> {
220        self.as_slice().peek_byte()
221    }
222
223    #[inline]
224    fn advance(&mut self, n: usize) -> ReadResult<()> {
225        if n > self.len() {
226            return Err(ReadError::IoError(std::io::ErrorKind::UnexpectedEof));
227        }
228        self.drain(..n);
229        Ok(())
230    }
231
232    #[inline]
233    fn read_byte(&mut self) -> ReadResult<u8> {
234        let b = self.peek_byte()?;
235        self.advance(1)?;
236        Ok(b)
237    }
238
239    #[inline]
240    fn read_slice(&mut self, len: usize) -> ReadResult<Cow<'data, [u8]>> {
241        if len > self.len() {
242            return Err(ReadError::IoError(std::io::ErrorKind::UnexpectedEof));
243        }
244        let end = self.split_off(len);
245        Ok(Cow::Owned(std::mem::replace(self, end)))
246    }
247
248    #[inline]
249    /// Careful, this double copies, hurting the performance quite a bit. Prefer using a StdReader for this
250    fn read_array<const N: usize>(&mut self) -> ReadResult<Cow<'data, [u8; N]>> {
251        if N > self.len() {
252            return Err(ReadError::IoError(std::io::ErrorKind::UnexpectedEof));
253        }
254
255        let end = self.split_off(N);
256        let target = std::mem::replace(self, end);
257        let mut array = [0u8; N];
258        array.copy_from_slice(&target);
259        Ok(Cow::Owned(array))
260    }
261
262    fn read_till_eof(&mut self) -> ReadResult<Cow<'data, [u8]>> {
263        Ok(Cow::Owned(std::mem::take(self)))
264    }
265}
266
267impl<'data> Read<'data> for Cow<'data, [u8]> {
268    #[inline]
269    fn peek_byte(&mut self) -> ReadResult<u8> {
270        match self {
271            Cow::Borrowed(slice) => slice.peek_byte(),
272            Cow::Owned(vec) => vec.as_slice().peek_byte(),
273        }
274    }
275
276    #[inline]
277    fn advance(&mut self, n: usize) -> ReadResult<()> {
278        match self {
279            Cow::Borrowed(slice) => slice.advance(n),
280            Cow::Owned(vec) => vec.advance(n),
281        }
282    }
283
284    #[inline]
285    fn read_byte(&mut self) -> ReadResult<u8> {
286        match self {
287            Cow::Borrowed(slice) => slice.read_byte(),
288            Cow::Owned(vec) => vec.read_byte(),
289        }
290    }
291
292    #[inline]
293    fn read_slice<'a>(&'a mut self, len: usize) -> ReadResult<Cow<'data, [u8]>> {
294        match self {
295            Cow::Borrowed(slice) => slice.read_slice(len),
296            Cow::Owned(vec) => vec.read_slice(len),
297        }
298    }
299
300    #[inline]
301    fn read_array<const N: usize>(&mut self) -> ReadResult<Cow<'data, [u8; N]>> {
302        match self {
303            Cow::Borrowed(slice) => slice.read_array(),
304            Cow::Owned(vec) => vec.read_array(),
305        }
306    }
307
308    #[inline]
309    fn read_till_eof(&mut self) -> ReadResult<Cow<'data, [u8]>> {
310        match self {
311            Cow::Borrowed(slice) => slice.read_till_eof(),
312            Cow::Owned(vec) => vec.read_till_eof(),
313        }
314    }
315}
316
317#[derive(Debug)]
318#[repr(transparent)]
319/// Wrapper around any [`std::io::Read`] type, necessary not to conflict with the implementation on [`&[u8]`]
320///
321/// ## Warning
322///
323/// This is not zero-copy!
324pub struct StdReader<R: std::io::Read>(std::io::BufReader<R>);
325
326impl<R: std::io::Read> StdReader<R> {
327    #[inline(always)]
328    pub fn new(buf_reader: std::io::BufReader<R>) -> Self {
329        Self::from(buf_reader)
330    }
331
332    #[inline(always)]
333    pub fn into_inner(self) -> std::io::BufReader<R> {
334        self.0
335    }
336
337    #[inline]
338    fn require_buffer_filled(&mut self, len: usize) -> Result<(), std::io::ErrorKind> {
339        if self.0.buffer().len() >= len {
340            return Ok(());
341        }
342        use std::io::BufRead as _;
343
344        let buf = self.0.fill_buf().map_err(|e| e.kind())?;
345
346        if buf.len() >= len {
347            Ok(())
348        } else {
349            Err(std::io::ErrorKind::UnexpectedEof)
350        }
351    }
352}
353
354impl<R: std::io::Read> From<std::io::BufReader<R>> for StdReader<R> {
355    #[inline(always)]
356    fn from(value: std::io::BufReader<R>) -> Self {
357        Self(value)
358    }
359}
360
361impl<'data, T: std::io::Read> Read<'data> for StdReader<T> {
362    #[inline]
363    fn peek_byte(&mut self) -> ReadResult<u8> {
364        self.require_buffer_filled(1).map_err(ReadError::IoError)?;
365        let b = unsafe { *self.0.buffer().as_ptr() };
366        Ok(b)
367    }
368
369    #[inline]
370    fn advance(&mut self, n: usize) -> ReadResult<()> {
371        use std::io::BufRead as _;
372        self.0.consume(n);
373        Ok(())
374    }
375
376    #[inline]
377    fn read_byte(&mut self) -> ReadResult<u8> {
378        use std::io::Read as _;
379        let mut b = 0u8;
380        self.0.read_exact(std::slice::from_mut(&mut b))?;
381        Ok(b)
382    }
383
384    #[inline]
385    fn read_slice<'a>(&'a mut self, len: usize) -> ReadResult<Cow<'data, [u8]>> {
386        use std::io::Read as _;
387        let mut buf = vec![0; len];
388        self.0.read_exact(&mut buf)?;
389        Ok(Cow::Owned(buf))
390    }
391
392    #[inline]
393    fn read_array<const N: usize>(&mut self) -> ReadResult<Cow<'data, [u8; N]>> {
394        use std::io::Read as _;
395        let mut arr = [0; N];
396        self.0.read_exact(&mut arr)?;
397        Ok(Cow::Owned(arr))
398    }
399
400    #[inline]
401    fn read_till_eof(&mut self) -> ReadResult<Cow<'data, [u8]>> {
402        use std::io::Read as _;
403        let mut buf = vec![];
404        self.0.read_to_end(&mut buf)?;
405        Ok(Cow::Owned(buf))
406    }
407}
408
409// Blanket fwd impls for std::io stuff
410impl<T: std::io::Read> std::io::Read for StdReader<T> {
411    #[inline(always)]
412    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
413        self.0.read(buf)
414    }
415}
416
417impl<T: std::io::Read> std::io::Seek for StdReader<T>
418where
419    T: std::io::Seek,
420{
421    #[inline(always)]
422    fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
423        self.0.seek(pos)
424    }
425}
426
427impl<T: std::io::BufRead> std::io::BufRead for StdReader<T> {
428    #[inline(always)]
429    fn fill_buf(&mut self) -> std::io::Result<&[u8]> {
430        self.0.fill_buf()
431    }
432
433    #[inline(always)]
434    fn consume(&mut self, amount: usize) {
435        self.0.consume(amount)
436    }
437}