Skip to main content

qubit_io/wrappers/
counting_reader.rs

1// =============================================================================
2//    Copyright (c) 2026 Haixing Hu.
3//
4//    SPDX-License-Identifier: Apache-2.0
5//
6//    Licensed under the Apache License, Version 2.0.
7// =============================================================================
8use std::io::{
9    BufRead,
10    Read,
11    Result,
12    Seek,
13    SeekFrom,
14};
15
16/// Reader wrapper that counts successfully read bytes.
17///
18/// The count is increased only after the wrapped reader reports a successful
19/// byte count. Failed reads do not change the counter.
20///
21/// # Examples
22/// ```
23/// use std::io::{
24///     Cursor,
25///     Read,
26/// };
27///
28/// use qubit_io::CountingReader;
29///
30/// let mut reader = CountingReader::new(Cursor::new(b"abc"));
31/// let mut data = Vec::new();
32/// reader.read_to_end(&mut data)?;
33///
34/// assert_eq!(b"abc", data.as_slice());
35/// assert_eq!(3, reader.bytes_read());
36/// # Ok::<(), std::io::Error>(())
37/// ```
38pub struct CountingReader<R> {
39    inner: R,
40    bytes_read: u64,
41}
42
43impl<R> CountingReader<R> {
44    /// Creates a counting reader.
45    ///
46    /// # Parameters
47    /// - `inner`: Reader to wrap.
48    ///
49    /// # Returns
50    /// A new counting reader with a zero byte count.
51    #[inline]
52    pub fn new(inner: R) -> Self {
53        Self {
54            inner,
55            bytes_read: 0,
56        }
57    }
58
59    /// Returns the number of bytes successfully read through this wrapper.
60    ///
61    /// # Returns
62    /// Total byte count. The value saturates at [`u64::MAX`].
63    #[inline]
64    pub fn bytes_read(&self) -> u64 {
65        self.bytes_read
66    }
67
68    /// Returns an immutable reference to the wrapped reader.
69    ///
70    /// # Returns
71    /// The wrapped reader reference.
72    #[inline]
73    pub fn get_ref(&self) -> &R {
74        &self.inner
75    }
76
77    /// Returns a mutable reference to the wrapped reader.
78    ///
79    /// # Returns
80    /// The wrapped reader reference.
81    #[inline]
82    pub fn get_mut(&mut self) -> &mut R {
83        &mut self.inner
84    }
85
86    /// Consumes this wrapper and returns the wrapped reader.
87    ///
88    /// # Returns
89    /// The wrapped reader.
90    #[inline]
91    pub fn into_inner(self) -> R {
92        self.inner
93    }
94}
95
96impl<R> Read for CountingReader<R>
97where
98    R: Read,
99{
100    fn read(&mut self, buffer: &mut [u8]) -> Result<usize> {
101        let count = self.inner.read(buffer)?;
102        self.bytes_read = self.bytes_read.saturating_add(count as u64);
103        Ok(count)
104    }
105}
106
107impl<R> BufRead for CountingReader<R>
108where
109    R: BufRead,
110{
111    #[inline]
112    fn fill_buf(&mut self) -> Result<&[u8]> {
113        self.inner.fill_buf()
114    }
115
116    #[inline]
117    fn consume(&mut self, amount: usize) {
118        self.bytes_read = self.bytes_read.saturating_add(amount as u64);
119        self.inner.consume(amount);
120    }
121}
122
123impl<R> Seek for CountingReader<R>
124where
125    R: Seek,
126{
127    #[inline]
128    fn seek(&mut self, position: SeekFrom) -> Result<u64> {
129        self.inner.seek(position)
130    }
131}