Skip to main content

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