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}