Skip to main content

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}