slice_of_bytes_reader/
lib.rs1#![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}