Skip to main content

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