concat_reader/
read.rs

1use crate::ConcatRead;
2use std::fmt;
3use std::io::{Read, Result};
4
5/// The `ConcatReader` struct allows to read from multiple readers in a sequential order.
6///
7/// If the current reader reaches its `EOF` the `ConcatReader` will start reading from the next
8/// reader in the iterator. If all readers reached `EOF` the `ConcatReader` will also be `EOF`.
9///
10/// # Examples
11/// ```no_run
12/// use concat_reader::*;
13/// use std::fs::File;
14/// use std::io;
15/// use std::io::prelude::*;
16///
17/// fn main() -> io::Result<()> {
18///     let foo = File::open("foo.txt")?;
19///     let bar = File::open("bar.txt")?;
20///     let baz = File::open("bar.txt")?;
21///     let files = [foo, bar, baz];
22///     let mut c = ConcatReader::new(&files);
23///     let mut buffer = [0; 10];
24///
25///     // read up to 10 bytes
26///     let n = c.read(&mut buffer[..])?;
27///
28///     println!("The bytes: {:?}", &buffer[..n]);
29///
30///     //skip to the next file
31///     c.skip();
32///
33///     let mut buffer = Vec::new();
34///     // read all rest files into a single buffer
35///     c.read_to_end(&mut buffer)?;
36///     Ok(())
37/// }
38/// ```
39pub struct ConcatReader<I: IntoIterator> {
40    curr: Option<I::Item>,
41    iter: I::IntoIter,
42}
43
44impl<I> ConcatReader<I>
45where
46    I: IntoIterator,
47    I::Item: Read,
48{
49    /// Creates a new `ConcatReader` from an value which can be converted into an `Iterator<Item=Read>`.
50    ///
51    /// ```
52    /// use std::io::prelude::*;
53    /// use concat_reader::{ConcatRead, ConcatReader};
54    /// let bytes = vec!["first".as_bytes(), "second".as_bytes()];
55    /// let r = ConcatReader::new(bytes);
56    /// ```
57    pub fn new(iter: I) -> Self {
58        let mut iter = iter.into_iter();
59        let curr = iter.next();
60        Self { iter, curr }
61    }
62}
63
64impl<I> ConcatRead for ConcatReader<I>
65where
66    I: IntoIterator,
67    I::Item: Read,
68{
69    type Item = I::Item;
70
71    fn current(&self) -> Option<&Self::Item> {
72        self.curr.as_ref()
73    }
74
75    fn skip(&mut self) -> bool {
76        self.curr = self.iter.next();
77        self.curr.is_some()
78    }
79}
80
81impl<I> From<I> for ConcatReader<I>
82where
83    I: IntoIterator,
84    I::Item: Read,
85{
86    fn from(iter: I) -> ConcatReader<I> {
87        Self::new(iter)
88    }
89}
90
91impl<I> Read for ConcatReader<I>
92where
93    I: IntoIterator,
94    I::Item: Read,
95{
96    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
97        let n = match self.curr {
98            None => 0,
99            Some(ref mut r) => r.read(buf)?,
100        };
101
102        if n > 0 || buf.is_empty() || self.curr.is_none() {
103            Ok(n)
104        } else {
105            self.curr = self.iter.next();
106            self.read(buf)
107        }
108    }
109}
110
111impl<I> fmt::Debug for ConcatReader<I>
112where
113    I: IntoIterator,
114    I::Item: fmt::Debug,
115    I::IntoIter: Clone,
116{
117    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
118        let rest: Vec<_> = self.iter.clone().collect();
119        f.debug_struct("Concat")
120            .field("curr", &self.curr)
121            .field("rest", &rest)
122            .finish()
123    }
124}
125
126#[cfg(test)]
127mod tests {
128    use crate::ConcatReader;
129    use std::io::prelude::*;
130
131    #[test]
132    fn reads_from_multiple_readers() {
133        let bytes: Vec<&[u8]> = vec![b"1", b"22", b"333", b"4444"];
134        let mut reader = ConcatReader::new(bytes);
135
136        let mut buf = [0; 5];
137        reader.read_exact(&mut buf).unwrap();
138        assert_eq!(&buf, b"12233");
139    }
140}