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 {
56 inner,
57 bytes_read: 0,
58 }
59 }
60
61 /// Returns the number of bytes successfully read through this wrapper.
62 ///
63 /// # Returns
64 /// Total byte count. The value saturates at [`u64::MAX`].
65 #[inline]
66 pub fn bytes_read(&self) -> u64 {
67 self.bytes_read
68 }
69
70 /// Returns an immutable reference to the wrapped reader.
71 ///
72 /// # Returns
73 /// The wrapped reader reference.
74 #[inline]
75 pub fn get_ref(&self) -> &R {
76 &self.inner
77 }
78
79 /// Returns a mutable reference to the wrapped reader.
80 ///
81 /// # Returns
82 /// The wrapped reader reference.
83 #[inline]
84 pub fn get_mut(&mut self) -> &mut R {
85 &mut self.inner
86 }
87
88 /// Consumes this wrapper and returns the wrapped reader.
89 ///
90 /// # Returns
91 /// The wrapped reader.
92 #[inline]
93 pub fn into_inner(self) -> R {
94 self.inner
95 }
96}
97
98impl<R> Read for CountingReader<R>
99where
100 R: Read,
101{
102 fn read(&mut self, buffer: &mut [u8]) -> Result<usize> {
103 let count = self.inner.read(buffer)?;
104 self.bytes_read = self.bytes_read.saturating_add(count as u64);
105 Ok(count)
106 }
107}
108
109impl<R> BufRead for CountingReader<R>
110where
111 R: BufRead,
112{
113 #[inline]
114 fn fill_buf(&mut self) -> Result<&[u8]> {
115 self.inner.fill_buf()
116 }
117
118 #[inline]
119 fn consume(&mut self, amount: usize) {
120 self.bytes_read = self.bytes_read.saturating_add(amount as u64);
121 self.inner.consume(amount);
122 }
123}
124
125impl<R> Seek for CountingReader<R>
126where
127 R: Seek,
128{
129 #[inline]
130 fn seek(&mut self, position: SeekFrom) -> Result<u64> {
131 self.inner.seek(position)
132 }
133}