use std::io::{BufRead, BufReader, Error, Read};
pub struct BytesIter<R: Read> {
buf_reader: BufReader<R>,
buf: Vec<u8>,
}
impl<R: Read> BytesIter<R> {
pub fn new(reader: R, size: usize) -> BytesIter<R> {
BytesIter {
buf_reader: BufReader::with_capacity(size, reader),
buf: Vec::with_capacity(size),
}
}
}
impl<R: Read> Iterator for BytesIter<R> {
type Item = Result<Vec<u8>, Error>;
fn next(&mut self) -> Option<Self::Item> {
let buf_len = self.buf.len();
if buf_len > 0 {
self.buf_reader.consume(buf_len);
self.buf.clear();
}
match self.buf_reader.fill_buf() {
Ok(buf) => {
if !buf.is_empty() {
self.buf.extend_from_slice(buf);
Some(Ok(self.buf.clone()))
} else {
None
}
}
Err(err) => Some(Err(err)),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
const DEFAULT_BUF_SIZE: usize = 8 * 1024;
fn sliced(b: &[u8], size: usize) -> Vec<Vec<u8>> {
let mut v = vec![];
let mut iter = BytesIter::new(b, size);
while let Some(chunk) = iter.next() {
v.push(chunk.unwrap().to_owned());
}
v
}
fn test<T: AsRef<[u8]>>(bytes: T, size: usize) {
let bytes = bytes.as_ref();
let a = sliced(bytes, size);
let b = bytes.chunks(size).collect::<Vec<_>>();
if a != b {
panic!(
"chunks are not equal!
read-byte-slice produced {} chunks with lengths: {:?}
slice.chunks produced {} chunks with lengths: {:?}",
a.len(),
a.iter().map(|c| c.len()).collect::<Vec<_>>(),
b.len(),
b.iter().map(|c| c.len()).collect::<Vec<_>>()
);
}
}
#[test]
fn test_simple() {
let bytes = b"0123456789abcdef";
test(bytes, 4);
}
#[test]
fn test_non_even() {
let bytes = b"0123456789abcd";
test(bytes, 4);
}
#[test]
fn test_chunks_larger_than_bufread_default_buffer() {
let bytes = (0..DEFAULT_BUF_SIZE * 4)
.map(|i| (i % 256) as u8)
.collect::<Vec<u8>>();
let size = DEFAULT_BUF_SIZE * 2;
test(bytes, size);
}
}