chain_reader/lib.rs
1use std::{
2 collections::VecDeque,
3 io::{self, Read},
4};
5
6/// A sequential chaining reader that combines multiple [`Read`] instances with configurable error handling.
7///
8/// # Behavior
9///
10/// - Readers are consumed in FIFO (first-in, first-out) order.
11/// - Automatically switches to the next reader when the current one reaches EOF (returns `Ok(0)`).
12/// - Allows custom error handling to decide whether to retry or skip on I/O errors.
13///
14/// # Comparison with [`io::Chain`]
15///
16/// - Supports a dynamic queue of readers instead of a fixed pair.
17/// - Configurable error handling strategies: Retry or Skip
18/// - Automatically advances to the next reader on EOF.
19///
20/// ---
21///
22/// 顺序管道读取器,将多个 [`Read`] 实例组合为具有可配置错误处理的顺序读取管道。
23///
24/// # 行为特性:
25///
26/// - 按先进先出顺序消费读取器。
27/// - 当前读取器到达 EOF 时(返回 `Ok(0)`)自动切换至下一个。
28/// - 允许自定义错误处理策略,决定在 I/O 错误时重试或跳过。
29///
30/// # 与 [`io::Chain`] 的区别:
31///
32/// - 支持动态读取器队列而非固定两个。
33/// - 可配置错误处理策略:重试或跳过。
34/// - EOF 时自动管理读取器切换。
35#[derive(Debug, Clone)]
36pub struct ChainReader<R, F>
37where
38 R: Read,
39 F: FnMut(io::Error) -> ErrorAction,
40{
41 /// Reader queue managed as FIFO buffer (first-in, first-out).
42 ///
43 /// Implemented with [`VecDeque`] for O(1) pop-front operations. The front reader
44 /// remains active until it returns EOF (`Ok(0)`), encounters an error handled by [`ErrorAction::Skip`],
45 /// or is explicitly removed.
46 ///
47 /// ---
48 ///
49 /// 先进先出读取器队列。
50 ///
51 /// 使用 [`VecDeque`] 实现 O(1) 复杂度前端弹出操作。队列首部的读取器保持激活状态,
52 /// 直到返回 EOF(`Ok(0)`)、遇到由 [`ErrorAction::Skip`] 处理的错误,或被显式移除。
53 fifo: VecDeque<R>,
54 /// Error handling callback for read operations.
55 ///
56 /// When a read error occurs, this callback is invoked with the encountered [`io::Error`].
57 /// The chaining behavior is determined by the returned [`ErrorAction`]:
58 /// - [`ErrorAction::Retry`]: Propagate the error but retain the current reader for retries.
59 /// - [`ErrorAction::Skip`]: Discard the current reader and proceed to the next.
60 ///
61 /// ---
62 ///
63 /// 读取操作错误处理回调。
64 ///
65 /// 当读取错误发生时,此回调函数接收遇到的 [`io::Error`],
66 /// 并通过返回的 [`ErrorAction`] 决定链式读取行为:
67 /// - [`ErrorAction::Retry`]:传播错误但保留当前读取器以供重试。
68 /// - [`ErrorAction::Skip`]:跳过当前读取器并继续下一个。
69 handle: F,
70}
71
72impl<R, F> ChainReader<R, F>
73where
74 R: Read,
75 F: FnMut(io::Error) -> ErrorAction,
76{
77 /// Creates a new `ChainReader` with the given reader queue and error handler.
78 ///
79 /// The readers will be consumed in the order they appear in the `readers` queue.
80 /// The `handle` callback determines behavior on I/O errors during reading.
81 ///
82 /// # Parameters
83 /// - `readers`: Queue of readers to process sequentially
84 /// - `handle`: Error handling strategy callback
85 ///
86 /// # Examples
87 /// ```
88 /// use std::collections::VecDeque;
89 /// use std::io;
90 /// use chain_reader::{ChainReader, ErrorAction};
91 ///
92 /// let mut readers = VecDeque::new();
93 /// readers.push_back("hello".as_bytes());
94 /// let error_handler = |e: io::Error| ErrorAction::Skip;
95 /// let chain = ChainReader::new(readers, error_handler);
96 /// ```
97 ///
98 /// ---
99 ///
100 /// 使用指定的读取器队列和错误处理回调创建新的 `ChainReader`
101 ///
102 /// 读取器将按照队列中的顺序被消费。`handle` 回调用于决定读取时遇到 I/O 错误的处理策略
103 ///
104 /// # 参数
105 /// - `readers`: 要顺序处理的读取器队列
106 /// - `handle`: 错误处理策略回调
107 ///
108 /// # 示例
109 /// ```
110 /// use std::collections::VecDeque;
111 /// use std::io;
112 /// use chain_reader::{ChainReader, ErrorAction};
113 ///
114 /// let mut readers = VecDeque::new();
115 /// readers.push_back("hello".as_bytes());
116 /// let error_handler = |e: io::Error| ErrorAction::Skip;
117 /// let chain = ChainReader::new(readers, error_handler);
118 /// ```
119 pub fn new(readers: VecDeque<R>, handle: F) -> Self {
120 ChainReader {
121 fifo: readers,
122 handle,
123 }
124 }
125
126 /// Appends a reader to the end of the processing queue
127 ///
128 /// The reader will be processed after all existing readers in the queue
129 /// have either reached EOF or been skipped due to errors.
130 ///
131 /// # Parameters
132 /// - `reader`: Reader to add to the end of the queue
133 ///
134 /// # Examples
135 /// ```
136 /// use std::collections::VecDeque;
137 /// use std::io;
138 /// use chain_reader::{ChainReader, ErrorAction};
139 ///
140 /// let mut chain = ChainReader::new(VecDeque::new(), |e| ErrorAction::Skip);
141 /// chain.push_back(std::io::empty());
142 /// ```
143 ///
144 /// ---
145 ///
146 /// 将读取器追加到处理队列末尾
147 ///
148 /// 该读取器将在队列中所有现有读取器处理完毕(到达 EOF 或因为错误被跳过)后进行处理
149 ///
150 /// # 参数
151 /// - `reader`: 要添加到队列末尾的读取器
152 ///
153 /// # 示例
154 /// ```
155 /// use std::collections::VecDeque;
156 /// use std::io;
157 /// use chain_reader::{ChainReader, ErrorAction};
158 /// let mut chain = ChainReader::new(VecDeque::new(), |e| ErrorAction::Skip);
159 /// chain.push_back(std::io::empty());
160 /// ```
161 pub fn push_back(&mut self, reader: R) {
162 self.fifo.push_back(reader);
163 }
164
165 /// Removes and returns the front reader from the queue
166 ///
167 /// Used internally when advancing to the next reader. Maintains
168 /// O(1) time complexity for queue operations.
169 ///
170 /// ---
171 ///
172 /// 移除并返回队列前端的读取器
173 ///
174 /// 内部用于切换到下一个读取器,保持队列操作的 O(1) 时间复杂度
175 fn pop_front(&mut self) -> Option<R> {
176 self.fifo.pop_front()
177 }
178}
179
180impl<R, F> Read for ChainReader<R, F>
181where
182 R: Read,
183 F: FnMut(io::Error) -> ErrorAction,
184{
185 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
186 loop {
187 let reader = match self.fifo.front_mut() {
188 Some(it) => it,
189 None => return Ok(0),
190 };
191
192 match reader.read(buf) {
193 Ok(0) => {
194 let _ = self.pop_front();
195 }
196 Ok(it) => {
197 return Ok(it);
198 }
199 Err(it) => {
200 let r: ErrorAction = (self.handle)(it);
201 match r {
202 ErrorAction::Retry(it) => return Err(it),
203 ErrorAction::Skip => {
204 let _ = self.pop_front();
205 }
206 }
207 }
208 }
209 }
210 }
211}
212
213/// Defines the action to take when a read error occurs.
214///
215/// ---
216///
217/// 定义读取错误发生时的处理动作。
218pub enum ErrorAction {
219 /// Propagate the error but retain the current reader.
220 ///
221 /// The next read operation will retry the same reader. This is useful for
222 /// transient errors where retrying might succeed.
223 ///
224 /// ---
225 ///
226 /// 传播错误但保留当前读取器。
227 ///
228 /// 下次读取操作将继续尝试同一读取器。适用于可能通过重试解决的临时错误。
229 Retry(io::Error),
230 /// Discard the current reader and proceed to the next one.
231 ///
232 /// The problematic reader is removed from the queue immediately.
233 ///
234 /// ---
235 ///
236 /// 丢弃当前读取器并继续下一个。
237 ///
238 /// 有问题的读取器将立即从队列中移除。
239 Skip,
240}