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}