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}