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
use std::io::{self, Read};
use iowrap::ReadMany;
/// The number of bytes that are read from the reader at once.
const READER_CHUNK_SIZE: usize = 4096;
// Based on
// https://stackoverflow.com/questions/73145503/iterator-for-reading-file-chunks/73145594#73145594
/// Chunks the given reader to the given size.
///
/// If the end is reached and there are a few bytes left, that don't fill a full chunk, those bytes
/// are returned.
pub struct ChunkIterator<R> {
reader: R,
chunk_size: usize,
}
impl<R: Read> ChunkIterator<R> {
/// Return a new iterator with a default chunk size of 4KiB.
pub fn new(reader: R) -> Self {
Self {
reader,
chunk_size: READER_CHUNK_SIZE,
}
}
pub const fn chunk_size(&self) -> usize {
self.chunk_size
}
}
impl<R: Read> Iterator for ChunkIterator<R> {
type Item = io::Result<Vec<u8>>;
fn next(&mut self) -> Option<Self::Item> {
let mut buffer = vec![0u8; self.chunk_size];
match self.reader.read_many(&mut buffer) {
Ok(bytes_read) if bytes_read == self.chunk_size => Some(Ok(buffer)),
// A position of 0 indicates end of file.
Ok(bytes_read) if bytes_read == 0 => None,
Ok(bytes_read) => Some(Ok(buffer[..bytes_read].to_vec())),
Err(error) => Some(Err(error)),
}
}
}