Skip to main content

qubit_io/wrappers/
limit_reader.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2026 Haixing Hu.
4 *
5 *    SPDX-License-Identifier: Apache-2.0
6 *
7 *    Licensed under the Apache License, Version 2.0.
8 *
9 ******************************************************************************/
10use std::io::{
11    BufRead,
12    Read,
13    Result,
14};
15
16/// Reader wrapper that exposes at most a fixed number of bytes.
17///
18/// `LimitReader` is useful when a parser must consume a bounded section of a
19/// larger stream without relying on the caller to provide a pre-sliced buffer.
20/// Once the remaining limit reaches zero, reads return `Ok(0)` without touching
21/// the inner reader.
22///
23/// # Examples
24/// ```
25/// use std::io::{
26///     Cursor,
27///     Read,
28/// };
29///
30/// use qubit_io::LimitReader;
31///
32/// let mut reader = LimitReader::new(Cursor::new(b"abcdef"), 3);
33/// let mut data = Vec::new();
34/// reader.read_to_end(&mut data)?;
35///
36/// assert_eq!(b"abc", data.as_slice());
37/// assert_eq!(0, reader.remaining());
38/// # Ok::<(), std::io::Error>(())
39/// ```
40pub struct LimitReader<R> {
41    inner: R,
42    remaining: u64,
43}
44
45impl<R> LimitReader<R> {
46    /// Creates a reader that exposes at most `limit` bytes from `inner`.
47    ///
48    /// # Parameters
49    /// - `inner`: Reader to wrap.
50    /// - `limit`: Maximum number of bytes that may be read through this wrapper.
51    ///
52    /// # Returns
53    /// A new limited reader.
54    #[inline]
55    pub fn new(inner: R, limit: u64) -> Self {
56        Self {
57            inner,
58            remaining: limit,
59        }
60    }
61
62    /// Returns the number of bytes still available through this wrapper.
63    ///
64    /// # Returns
65    /// Remaining readable byte count before the wrapper reports EOF.
66    #[inline]
67    pub fn remaining(&self) -> u64 {
68        self.remaining
69    }
70
71    /// Returns an immutable reference to the wrapped reader.
72    ///
73    /// # Returns
74    /// The wrapped reader reference.
75    #[inline]
76    pub fn get_ref(&self) -> &R {
77        &self.inner
78    }
79
80    /// Returns a mutable reference to the wrapped reader.
81    ///
82    /// # Returns
83    /// The wrapped reader reference.
84    #[inline]
85    pub fn get_mut(&mut self) -> &mut R {
86        &mut self.inner
87    }
88
89    /// Consumes this wrapper and returns the wrapped reader.
90    ///
91    /// # Returns
92    /// The wrapped reader.
93    #[inline]
94    pub fn into_inner(self) -> R {
95        self.inner
96    }
97}
98
99impl<R> Read for LimitReader<R>
100where
101    R: Read,
102{
103    fn read(&mut self, buffer: &mut [u8]) -> Result<usize> {
104        if self.remaining == 0 || buffer.is_empty() {
105            return Ok(0);
106        }
107        let requested = self.remaining.min(buffer.len() as u64) as usize;
108        let count = self.inner.read(&mut buffer[..requested])?;
109        self.remaining -= count as u64;
110        Ok(count)
111    }
112}
113
114impl<R> BufRead for LimitReader<R>
115where
116    R: BufRead,
117{
118    fn fill_buf(&mut self) -> Result<&[u8]> {
119        if self.remaining == 0 {
120            return Ok(&[]);
121        }
122        let buffer = self.inner.fill_buf()?;
123        let limit = self.remaining.min(buffer.len() as u64) as usize;
124        Ok(&buffer[..limit])
125    }
126
127    fn consume(&mut self, amount: usize) {
128        let count = self.remaining.min(amount as u64);
129        self.remaining -= count;
130        self.inner.consume(count as usize);
131    }
132}