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}