use std::io::{self, BufRead, Read};
use crate::stream::raw::{InBuffer, Operation, OutBuffer};
pub struct Reader<R, D> {
reader: R,
operation: D,
state: State,
single_frame: bool,
finished_frame: bool,
}
enum State {
Reading,
PastEof,
Finished,
}
impl<R, D> Reader<R, D> {
pub fn new(reader: R, operation: D) -> Self {
Reader {
reader,
operation,
state: State::Reading,
single_frame: false,
finished_frame: false,
}
}
pub fn set_single_frame(&mut self) {
self.single_frame = true;
}
pub fn operation_mut(&mut self) -> &mut D {
&mut self.operation
}
pub fn reader_mut(&mut self) -> &mut R {
&mut self.reader
}
pub fn reader(&self) -> &R {
&self.reader
}
pub fn into_inner(self) -> R {
self.reader
}
pub fn flush(&mut self, output: &mut [u8]) -> io::Result<usize>
where
D: Operation,
{
self.operation.flush(&mut OutBuffer::around(output))
}
}
fn fill_buf<R>(reader: &mut R) -> io::Result<&[u8]>
where
R: BufRead,
{
let res = reader.fill_buf()?;
Ok(res)
}
impl<R, D> Read for Reader<R, D>
where
R: BufRead,
D: Operation,
{
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let mut first = true;
loop {
match self.state {
State::Reading => {
let (bytes_read, bytes_written) = {
let input = if first {
b""
} else {
fill_buf(&mut self.reader)?
};
if !first && input.is_empty() {
self.state = State::PastEof;
continue;
}
first = false;
let mut src = InBuffer::around(input);
let mut dst = OutBuffer::around(buf);
if self.finished_frame && !input.is_empty() {
self.operation.reinit()?;
self.finished_frame = false;
}
let hint = self.operation.run(&mut src, &mut dst)?;
if hint == 0 {
self.finished_frame = true;
if self.single_frame {
self.state = State::Finished;
}
}
(src.pos(), dst.pos())
};
self.reader.consume(bytes_read);
if bytes_written > 0 {
return Ok(bytes_written);
}
}
State::PastEof => {
let mut dst = OutBuffer::around(buf);
let hint = self
.operation
.finish(&mut dst, self.finished_frame)?;
if hint == 0 {
self.state = State::Finished;
}
return Ok(dst.pos());
}
State::Finished => {
return Ok(0);
}
}
}
}
}
#[cfg(test)]
mod tests {
use super::Reader;
use std::io::{Cursor, Read};
#[test]
fn test_noop() {
use crate::stream::raw::NoOp;
let input = b"AbcdefghAbcdefgh.";
let mut output = Vec::new();
{
let mut reader = Reader::new(Cursor::new(input), NoOp);
reader.read_to_end(&mut output).unwrap();
}
assert_eq!(&output, input);
}
#[test]
fn test_compress() {
use crate::stream::raw::Encoder;
let input = b"AbcdefghAbcdefgh.";
let mut output = Vec::new();
{
let mut reader =
Reader::new(Cursor::new(input), Encoder::new(1).unwrap());
reader.read_to_end(&mut output).unwrap();
}
let decoded = crate::decode_all(&output[..]).unwrap();
assert_eq!(&decoded, input);
}
}