use flate2::read::GzDecoder;
use std::{
fs::File,
io::{self, prelude::*},
};
enum FileType {
GZ(io::BufReader<GzDecoder<File>>),
NOGZ(io::BufReader<File>),
}
pub struct ResultLinesIterator {
reader: FileType,
}
impl ResultLinesIterator {
pub fn open(path: impl AsRef<std::path::Path>) -> io::Result<Self> {
match path.as_ref().extension() {
Some(ext) if ext == "gz" => {
let file = File::open(path)?;
let gz_decoder = GzDecoder::new(file);
let reader = io::BufReader::new(gz_decoder);
Ok(Self {
reader: FileType::GZ(reader),
})
}
_ => {
let file = File::open(path)?;
let reader = io::BufReader::new(file);
Ok(Self {
reader: FileType::NOGZ(reader),
})
}
}
}
}
impl Iterator for ResultLinesIterator {
type Item = io::Result<Vec<u8>>;
fn next(&mut self) -> Option<Self::Item> {
let mut buffer = Vec::with_capacity(1024);
let size_read = match &mut self.reader {
FileType::GZ(x) => x.read_until(b'\n', &mut buffer),
FileType::NOGZ(x) => x.read_until(b'\n', &mut buffer),
};
match size_read {
Err(e) => Some(Err(e)),
Ok(size) => match size {
0 => None,
_ => {
if buffer[buffer.len() - 1] == b'\n' {
buffer.pop();
}
Some(Ok(buffer))
}
},
}
}
}
pub struct LinesIterator<I>
where
I: Iterator<Item = io::Result<Vec<u8>>>,
{
lines_iterator: I,
}
impl<I> LinesIterator<I>
where
I: Iterator<Item = io::Result<Vec<u8>>>,
{
pub fn from(lines_iterator: I) -> Self {
Self { lines_iterator }
}
}
impl<I> Iterator for LinesIterator<I>
where
I: Iterator<Item = io::Result<Vec<u8>>>,
{
type Item = Vec<u8>;
fn next(&mut self) -> Option<Self::Item> {
let line_or_error = self.lines_iterator.next()?;
let line = line_or_error.expect("A line could not be read due to an IO error.");
Some(line)
}
}