1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
use std::io::{self, Read};
pub struct CatRead<T, F> {
source: F,
current: T,
}
impl<T, F> CatRead<T, F>
where
T: Read,
F: FnMut() -> Option<io::Result<T>>,
{
pub fn new(mut source: F) -> io::Result<Self> {
let current = source()
.transpose()?
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "no sources"))?;
Ok(Self { source, current })
}
}
impl<T, F> Read for CatRead<T, F>
where
T: Read,
F: FnMut() -> Option<io::Result<T>>,
{
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
let mut bytes_read = 0;
loop {
match self.current.read(&mut buf[bytes_read..]) {
Ok(0) => match (self.source)() {
Some(source) => self.current = source?,
None => return Ok(bytes_read),
}
Ok(len) => {
bytes_read += len;
if bytes_read == buf.len() {
return Ok(bytes_read);
}
}
Err(e) if e.kind() == io::ErrorKind::Interrupted => (),
Err(e) => return Err(e),
}
}
}
}
#[cfg(test)]
mod tests {
use std::io::{self, Cursor, Read};
use crate::CatRead;
#[test]
fn it_works() {
let sources = &["Hello, ", "world!"];
let mut sources = sources.iter().map(Cursor::new);
let catread = CatRead::new(|| sources.next().map(Ok)).unwrap();
let actual = read_to_string(catread).unwrap();
assert_eq!(actual, "Hello, world!");
}
fn read_to_string(mut reader: impl Read) -> io::Result<String> {
let mut buf = String::new();
reader.read_to_string(&mut buf)?;
Ok(buf)
}
}