countio/counter/
mod.rs

1#[cfg(feature = "std")]
2#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
3mod stdlib;
4
5#[cfg(feature = "futures")]
6#[cfg_attr(docsrs, doc(cfg(feature = "futures")))]
7mod futures;
8
9#[cfg(feature = "tokio")]
10#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
11mod tokio;
12
13/// A wrapper that adds byte counting functionality to any reader, writer, or seeker.
14///
15/// `Counter<D>` tracks the total number of bytes read from and written to the underlying
16/// I/O object, providing methods to query these statistics at any time.
17///
18/// # Type Parameter
19///
20/// * `D` - The underlying I/O object (reader, writer, or seeker)
21///
22/// # Examples
23///
24/// ## Basic Usage with `std::io`
25///
26/// ```rust
27/// use std::io::{Read, Write};
28/// use countio::Counter;
29///
30/// // Counting bytes read
31/// let data = b"Hello, World!";
32/// let mut reader = Counter::new(&data[..]);
33/// let mut buffer = [0u8; 5];
34/// reader.read(&mut buffer).unwrap();
35/// assert_eq!(reader.reader_bytes(), 5);
36///
37/// // Counting bytes written
38/// let mut writer = Counter::new(Vec::new());
39/// writer.write_all(b"Hello").unwrap();
40/// assert_eq!(writer.writer_bytes(), 5);
41/// ```
42///
43/// ## With Buffered I/O
44///
45/// ```rust
46/// use std::io::{BufRead, BufReader, BufWriter, Write};
47/// use countio::Counter;
48///
49/// // Buffered reading
50/// let data = "Line 1\nLine 2\nLine 3\n";
51/// let reader = BufReader::new(data.as_bytes());
52/// let mut counter = Counter::new(reader);
53/// let mut line = String::new();
54/// counter.read_line(&mut line).unwrap();
55/// assert_eq!(counter.reader_bytes(), 7);
56///
57/// // Buffered writing
58/// let writer = BufWriter::new(Vec::new());
59/// let mut counter = Counter::new(writer);
60/// counter.write_all(b"Hello, World!").unwrap();
61/// counter.flush().unwrap();
62/// assert_eq!(counter.writer_bytes(), 13);
63/// ```
64///
65/// # Performance
66///
67/// The overhead of byte counting is minimal - just an integer addition per I/O operation.
68/// The wrapper implements all relevant traits (`Read`, `Write`, `Seek`, etc.) by
69/// delegating to the inner object while tracking byte counts.
70pub struct Counter<D> {
71    pub(crate) inner: D,
72    pub(crate) reader_bytes: usize,
73    pub(crate) writer_bytes: usize,
74}
75
76impl<D> Counter<D> {
77    /// Creates a new `Counter<D>` wrapping the given I/O object with zero read/written bytes.
78    ///
79    /// # Arguments
80    ///
81    /// * `inner` - The I/O object to wrap (reader, writer, seeker, etc.)
82    ///
83    /// # Examples
84    ///
85    /// ```rust
86    /// use countio::Counter;
87    /// use std::io::Cursor;
88    ///
89    /// let data = vec![1, 2, 3, 4, 5];
90    /// let cursor = Cursor::new(data);
91    /// let counter = Counter::new(cursor);
92    ///
93    /// assert_eq!(counter.reader_bytes(), 0);
94    /// assert_eq!(counter.writer_bytes(), 0);
95    /// ```
96    #[inline]
97    pub const fn new(inner: D) -> Self {
98        Self::with_bytes(inner, 0, 0)
99    }
100
101    /// Creates a new `Counter<D>` with pre-existing read/written byte counts.
102    ///
103    /// This is useful when you want to continue counting from a previous session
104    /// or when wrapping an I/O object that has already processed some data.
105    ///
106    /// # Arguments
107    ///
108    /// * `inner` - The I/O object to wrap
109    /// * `reader_bytes` - Initial count of bytes read
110    /// * `writer_bytes` - Initial count of bytes written
111    ///
112    /// # Examples
113    ///
114    /// ```rust
115    /// use countio::Counter;
116    /// use std::io::Cursor;
117    ///
118    /// let data = vec![1, 2, 3, 4, 5];
119    /// let cursor = Cursor::new(data);
120    /// let counter = Counter::with_bytes(cursor, 100, 50);
121    ///
122    /// assert_eq!(counter.reader_bytes(), 100);
123    /// assert_eq!(counter.writer_bytes(), 50);
124    /// ```
125    #[inline]
126    pub const fn with_bytes(inner: D, reader_bytes: usize, writer_bytes: usize) -> Self {
127        Self {
128            inner,
129            reader_bytes,
130            writer_bytes,
131        }
132    }
133
134    /// Returns the total number of bytes read from the underlying I/O object.
135    ///
136    /// This count includes all bytes successfully read through any of the
137    /// `Read` or `BufRead` trait methods.
138    ///
139    /// # Examples
140    ///
141    /// ```rust
142    /// use std::io::Read;
143    /// use countio::Counter;
144    ///
145    /// let data = b"Hello, World!";
146    /// let mut reader = Counter::new(&data[..]);
147    /// let mut buffer = [0u8; 5];
148    ///
149    /// reader.read_exact(&mut buffer).unwrap();
150    /// assert_eq!(reader.reader_bytes(), 5);
151    /// assert_eq!(reader.writer_bytes(), 0);
152    /// ```
153    #[inline]
154    pub const fn reader_bytes(&self) -> usize {
155        self.reader_bytes
156    }
157
158    /// Returns the total number of bytes written to the underlying I/O object.
159    ///
160    /// This count includes all bytes successfully written through any of the
161    /// `Write` trait methods.
162    ///
163    /// # Examples
164    ///
165    /// ```rust
166    /// use std::io::Write;
167    /// use countio::Counter;
168    ///
169    /// let mut writer = Counter::new(Vec::new());
170    /// writer.write_all(b"Hello").unwrap();
171    /// writer.write_all(b", World!").unwrap();
172    ///
173    /// assert_eq!(writer.writer_bytes(), 13);
174    /// assert_eq!(writer.reader_bytes(), 0);
175    /// ```
176    #[inline]
177    pub const fn writer_bytes(&self) -> usize {
178        self.writer_bytes
179    }
180
181    /// Returns the total number of bytes processed (read + written) as a `u128`.
182    ///
183    /// This is the sum of all bytes that have been read from or written to
184    /// the underlying I/O object since the `Counter` was created. Using `u128`
185    /// prevents overflow issues that could occur with large byte counts.
186    ///
187    /// # Examples
188    ///
189    /// ```rust
190    /// use std::io::{Read, Write};
191    /// use countio::Counter;
192    ///
193    /// let mut counter = Counter::new(Vec::new());
194    /// counter.write_all(b"Hello").unwrap();
195    ///
196    /// let data = b"World";
197    /// let mut reader = Counter::new(&data[..]);
198    /// let mut buf = [0u8; 5];
199    /// reader.read(&mut buf).unwrap();
200    ///
201    /// assert_eq!(counter.total_bytes(), 5);
202    /// assert_eq!(reader.total_bytes(), 5);
203    /// ```
204    #[inline]
205    pub const fn total_bytes(&self) -> u128 {
206        (self.reader_bytes as u128) + (self.writer_bytes as u128)
207    }
208
209    /// Consumes the `Counter<D>` and returns the underlying I/O object.
210    ///
211    /// This is useful when you need to recover the original I/O object,
212    /// perhaps to pass it to code that doesn't know about the `Counter` wrapper.
213    ///
214    /// # Examples
215    ///
216    /// ```rust
217    /// use std::io::Write;
218    /// use countio::Counter;
219    ///
220    /// let original_writer = Vec::new();
221    /// let mut counter = Counter::new(original_writer);
222    /// counter.write_all(b"Hello").unwrap();
223    ///
224    /// let recovered_writer = counter.into_inner();
225    /// assert_eq!(recovered_writer, b"Hello");
226    /// ```
227    #[inline]
228    pub fn into_inner(self) -> D {
229        self.inner
230    }
231
232    /// Gets a reference to the underlying I/O object.
233    ///
234    /// This allows you to access the wrapped object's methods directly
235    /// without consuming the `Counter`.
236    ///
237    /// # Examples
238    ///
239    /// ```rust
240    /// use countio::Counter;
241    /// use std::io::Cursor;
242    ///
243    /// let data = vec![1, 2, 3, 4, 5];
244    /// let cursor = Cursor::new(data.clone());
245    /// let counter = Counter::new(cursor);
246    ///
247    /// assert_eq!(counter.get_ref().position(), 0);
248    /// ```
249    #[inline]
250    pub const fn get_ref(&self) -> &D {
251        &self.inner
252    }
253
254    /// Gets a mutable reference to the underlying I/O object.
255    ///
256    /// This allows you to modify the wrapped object directly. Note that
257    /// any bytes read or written through the direct reference will not
258    /// be counted by the `Counter`.
259    ///
260    /// # Examples
261    ///
262    /// ```rust
263    /// use countio::Counter;
264    /// use std::io::Cursor;
265    ///
266    /// let data = vec![1, 2, 3, 4, 5];
267    /// let cursor = Cursor::new(data);
268    /// let mut counter = Counter::new(cursor);
269    ///
270    /// counter.get_mut().set_position(2);
271    /// assert_eq!(counter.get_ref().position(), 2);
272    /// ```
273    #[inline]
274    pub const fn get_mut(&mut self) -> &mut D {
275        &mut self.inner
276    }
277
278    /// Resets the byte counters to zero without affecting the underlying I/O object.
279    ///
280    /// This is useful when you want to start counting from a fresh state
281    /// without recreating the wrapper or losing the underlying object's state.
282    ///
283    /// # Examples
284    ///
285    /// ```rust
286    /// use std::io::{Read, Write};
287    /// use countio::Counter;
288    ///
289    /// let mut counter = Counter::new(Vec::new());
290    /// counter.write_all(b"Hello").unwrap();
291    /// assert_eq!(counter.writer_bytes(), 5);
292    ///
293    /// counter.reset();
294    /// assert_eq!(counter.writer_bytes(), 0);
295    /// assert_eq!(counter.reader_bytes(), 0);
296    ///
297    /// // The underlying data is preserved
298    /// assert_eq!(counter.get_ref(), b"Hello");
299    /// ```
300    #[inline]
301    pub const fn reset(&mut self) {
302        self.reader_bytes = 0;
303        self.writer_bytes = 0;
304    }
305}
306
307impl<D> From<D> for Counter<D> {
308    #[inline]
309    fn from(inner: D) -> Self {
310        Self::new(inner)
311    }
312}
313
314impl<D: Clone> Clone for Counter<D> {
315    fn clone(&self) -> Self {
316        Self {
317            inner: self.inner.clone(),
318            reader_bytes: self.reader_bytes,
319            writer_bytes: self.writer_bytes,
320        }
321    }
322}
323
324impl<D: Default> Default for Counter<D> {
325    fn default() -> Self {
326        Self::new(D::default())
327    }
328}
329
330impl<D: core::fmt::Debug> core::fmt::Debug for Counter<D> {
331    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
332        f.debug_struct("Counter")
333            .field("inner", &self.inner)
334            .field("read", &self.reader_bytes)
335            .field("written", &self.writer_bytes)
336            .finish()
337    }
338}
339
340#[cfg(test)]
341mod tests {
342    use super::*;
343
344    #[test]
345    fn test_inner() {
346        let writer = vec![8u8];
347        assert_eq!(writer.len(), 1);
348
349        let mut writer = Counter::new(writer);
350        writer.get_mut().clear();
351        assert_eq!(writer.get_ref().len(), 0);
352
353        let writer = writer.into_inner();
354        assert_eq!(writer.len(), 0);
355    }
356
357    #[test]
358    fn test_from() {
359        let _: Counter<_> = Vec::<u8>::new().into();
360    }
361
362    #[test]
363    fn test_with_bytes_creates_counter_with_initial_counts() {
364        let counter = Counter::with_bytes(Vec::<u8>::new(), 100, 200);
365        assert_eq!(counter.reader_bytes(), 100);
366        assert_eq!(counter.writer_bytes(), 200);
367        assert_eq!(counter.total_bytes(), 300);
368    }
369
370    #[test]
371    fn test_reset() {
372        use std::io::Write;
373
374        let mut counter = Counter::new(Vec::new());
375        counter.write_all(b"Hello").unwrap();
376        assert_eq!(counter.writer_bytes(), 5);
377
378        counter.reset();
379        assert_eq!(counter.writer_bytes(), 0);
380        assert_eq!(counter.reader_bytes(), 0);
381        assert_eq!(counter.total_bytes(), 0);
382
383        // Data is preserved
384        assert_eq!(counter.get_ref(), b"Hello");
385    }
386
387    #[test]
388    fn test_clone() {
389        use std::io::Write;
390
391        let mut counter = Counter::new(Vec::new());
392        counter.write_all(b"Hello").unwrap();
393
394        let cloned = counter.clone();
395        assert_eq!(cloned.writer_bytes(), 5);
396        assert_eq!(cloned.get_ref(), b"Hello");
397    }
398
399    #[test]
400    fn test_default() {
401        let counter: Counter<Vec<u8>> = Counter::default();
402        assert_eq!(counter.reader_bytes(), 0);
403        assert_eq!(counter.writer_bytes(), 0);
404        assert!(counter.get_ref().is_empty());
405    }
406}