use crate::compressor::session::{EncoderSession, EncoderStatus, Operation};
use std::io::{Error, ErrorKind, Read, Result};
const FILL_CHUNK: usize = 64 * 1024;
pub struct EncoderReader<'c, 'd, R: Read> {
session: EncoderSession<'c, 'd>,
source: R,
input: Vec<u8>,
head: usize,
eof: bool,
finished: bool,
}
impl<R: Read> std::fmt::Debug for EncoderReader<'_, '_, R> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("EncoderReader")
.field("buffered", &(self.input.len() - self.head))
.field("eof", &self.eof)
.field("finished", &self.finished)
.finish_non_exhaustive()
}
}
impl<'c, 'd, R: Read> EncoderReader<'c, 'd, R> {
pub(crate) fn new(session: EncoderSession<'c, 'd>, source: R) -> Self {
Self {
session,
source,
input: Vec::new(),
head: 0,
eof: false,
finished: false,
}
}
pub const fn get_ref(&self) -> &R {
&self.source
}
pub const fn get_mut(&mut self) -> &mut R {
&mut self.source
}
pub const fn is_finished(&self) -> bool {
self.finished
}
#[must_use]
pub fn into_parts(self) -> EncoderReaderParts<R> {
let buffered_input = self.input.get(self.head..).unwrap_or_default().to_vec();
EncoderReaderParts {
inner: self.source,
buffered_input,
}
}
fn fill(&mut self) -> Result<()> {
self.input.clear();
self.head = 0;
loop {
self.input.resize(FILL_CHUNK, 0);
let outcome = self.source.read(&mut self.input);
match outcome {
Ok(0) => {
self.input.clear();
self.eof = true;
return Ok(());
}
Ok(count) => {
self.input.truncate(count);
return Ok(());
}
Err(error) if error.kind() == ErrorKind::Interrupted => {
self.input.clear();
}
Err(error) => {
self.input.clear();
return Err(error);
}
}
}
}
}
impl<R: Read> Read for EncoderReader<'_, '_, R> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
if buf.is_empty() || self.finished {
return Ok(0);
}
loop {
if self.head == self.input.len() && !self.eof {
self.fill()?;
}
let operation = if self.eof {
Operation::Finish
} else {
Operation::Process
};
let progress = {
let pending = self.input.get(self.head..).unwrap_or_default();
self.session
.process(pending, buf, operation)
.map_err(Error::from)?
};
self.head += progress.consumed;
if self.head == self.input.len() {
self.input.clear();
self.head = 0;
}
if progress.status == EncoderStatus::Finished {
self.finished = true;
}
if progress.produced > 0 {
return Ok(progress.produced);
}
if self.finished {
return Ok(0);
}
}
}
}
#[derive(Debug)]
pub struct EncoderReaderParts<R> {
pub inner: R,
pub buffered_input: Vec<u8>,
}