slice_of_bytes_reader/
lib.rs

1#![doc = include_str!("../README.md")]
2
3use std::io::{Error, Read};
4
5pub struct Reader<T, I> {
6    iter: I,
7    current_chunk_and_offset: Option<(T, usize)>,
8}
9
10impl<T, I> Reader<T, I>
11where
12    T: AsRef<[u8]>,
13    I: Iterator<Item = T>,
14{
15    pub fn new(mut iter: I) -> Self {
16        let current_chunk_and_offset = iter.next().map(|chunk| (chunk, 0));
17
18        Self {
19            iter,
20            current_chunk_and_offset,
21        }
22    }
23}
24
25impl<T, I> Read for Reader<T, I>
26where
27    T: AsRef<[u8]>,
28    I: Iterator<Item = T>,
29{
30    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
31        loop {
32            let Some((chunk, offset)) = self.current_chunk_and_offset.as_mut() else {
33                return Ok(0);
34            };
35
36            if chunk.as_ref().len() - *offset == 0 {
37                self.current_chunk_and_offset = self.iter.next().map(|chunk| (chunk, 0));
38                continue;
39            }
40
41            let chunk_remaining_len = chunk.as_ref().len() - *offset;
42
43            if chunk_remaining_len > buf.len() {
44                buf.copy_from_slice(&chunk.as_ref()[*offset..*offset + buf.len()]);
45                *offset += buf.len();
46                return Ok(buf.len());
47            } else {
48                buf[..chunk_remaining_len].copy_from_slice(&chunk.as_ref()[*offset..]);
49                self.current_chunk_and_offset = self.iter.next().map(|chunk| (chunk, 0));
50                return Ok(chunk_remaining_len);
51            }
52        }
53    }
54}
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59
60    #[test]
61    fn read() {
62        let chunks: &[&[u8]] = &[
63            b"", b"ab", b"", b"c", b"defg", b"", b"hij", b"klmnop", b"qrstuvw", b"", b"", b"xyz",
64            b"", b"",
65        ];
66
67        let mut reader = Reader::new(chunks.into_iter());
68        let mut result = String::new();
69        let total_length = reader.read_to_string(&mut result).unwrap();
70
71        assert_eq!(result, "abcdefghijklmnopqrstuvwxyz");
72        assert_eq!(total_length, 26);
73    }
74}