qubit_io/wrappers/tee_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 Read,
10 Result,
11 Seek,
12 SeekFrom,
13 Write,
14};
15
16/// Reader wrapper that mirrors read bytes into a branch writer.
17///
18/// `TeeReader` forwards reads to the source reader and writes every
19/// successfully read byte into the branch writer while the stream is consumed.
20/// If the branch writer fails, the source bytes have already been read from the
21/// inner reader and the branch error is returned.
22///
23/// Seeking a `TeeReader` seeks only the source reader. It does not seek or
24/// otherwise modify the branch writer; bytes mirrored after the seek are simply
25/// appended or written according to the branch writer's own state.
26///
27/// # Examples
28/// ```
29/// use std::io::{
30/// Cursor,
31/// Read,
32/// };
33///
34/// use qubit_io::TeeReader;
35///
36/// let source = Cursor::new(b"abc".to_vec());
37/// let branch = Vec::new();
38/// let mut reader = TeeReader::new(source, branch);
39///
40/// let mut data = Vec::new();
41/// reader.read_to_end(&mut data)?;
42/// let (_source, branch) = reader.into_inner();
43///
44/// assert_eq!(b"abc", data.as_slice());
45/// assert_eq!(b"abc", branch.as_slice());
46/// # Ok::<(), std::io::Error>(())
47/// ```
48pub struct TeeReader<R, W> {
49 reader: R,
50 branch: W,
51}
52
53impl<R, W> TeeReader<R, W> {
54 /// Creates a tee reader.
55 ///
56 /// # Parameters
57 /// - `reader`: Source reader.
58 /// - `branch`: Writer that receives the bytes successfully read.
59 ///
60 /// # Returns
61 /// A new tee reader.
62 #[inline]
63 pub fn new(reader: R, branch: W) -> Self {
64 Self { reader, branch }
65 }
66
67 /// Returns an immutable reference to the source reader.
68 ///
69 /// # Returns
70 /// The source reader reference.
71 #[inline]
72 pub fn reader_ref(&self) -> &R {
73 &self.reader
74 }
75
76 /// Returns a mutable reference to the source reader.
77 ///
78 /// # Returns
79 /// The source reader reference.
80 #[inline]
81 pub fn reader_mut(&mut self) -> &mut R {
82 &mut self.reader
83 }
84
85 /// Returns an immutable reference to the branch writer.
86 ///
87 /// # Returns
88 /// The branch writer reference.
89 #[inline]
90 pub fn branch_ref(&self) -> &W {
91 &self.branch
92 }
93
94 /// Returns a mutable reference to the branch writer.
95 ///
96 /// # Returns
97 /// The branch writer reference.
98 #[inline]
99 pub fn branch_mut(&mut self) -> &mut W {
100 &mut self.branch
101 }
102
103 /// Consumes this wrapper and returns the source reader and branch writer.
104 ///
105 /// # Returns
106 /// A tuple containing the source reader and branch writer.
107 #[inline]
108 pub fn into_inner(self) -> (R, W) {
109 (self.reader, self.branch)
110 }
111}
112
113impl<R, W> Read for TeeReader<R, W>
114where
115 R: Read,
116 W: Write,
117{
118 fn read(&mut self, buffer: &mut [u8]) -> Result<usize> {
119 let count = self.reader.read(buffer)?;
120 self.branch.write_all(&buffer[..count])?;
121 Ok(count)
122 }
123}
124
125impl<R, W> Seek for TeeReader<R, W>
126where
127 R: Seek,
128{
129 /// Seeks the source reader without touching the branch writer.
130 ///
131 /// # Parameters
132 /// - `position`: Target position for the source reader.
133 ///
134 /// # Returns
135 /// The new source reader position.
136 ///
137 /// # Errors
138 /// Returns the seek error reported by the source reader.
139 #[inline]
140 fn seek(&mut self, position: SeekFrom) -> Result<u64> {
141 self.reader.seek(position)
142 }
143}