use alloc::vec::Vec;
use std::io::{ErrorKind, Read, Result};
use crate::compressor::io::EncoderReaderParts;
use crate::compressor::parallel::{ParallelEncoderSession, ParallelEncoderStatus};
use crate::compressor::session::Operation;
const FILL_CHUNK: usize = 128 * 1024;
pub struct ParallelEncoderReader<'c, R: Read> {
session: ParallelEncoderSession<'c>,
source: R,
input: Vec<u8>,
head: usize,
end: usize,
eof: bool,
}
impl<R: Read> std::fmt::Debug for ParallelEncoderReader<'_, R> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ParallelEncoderReader")
.field("session", &self.session)
.field("buffered", &(self.end - self.head))
.field("eof", &self.eof)
.finish_non_exhaustive()
}
}
impl<'c, R: Read> ParallelEncoderReader<'c, R> {
pub(super) const fn new(session: ParallelEncoderSession<'c>, source: R) -> Self {
Self {
session,
source,
input: Vec::new(),
head: 0,
end: 0,
eof: false,
}
}
#[must_use]
pub const fn get_ref(&self) -> &R {
&self.source
}
pub const fn get_mut(&mut self) -> &mut R {
&mut self.source
}
#[must_use]
pub const fn is_finished(&self) -> bool {
self.session.is_finished()
}
#[must_use]
pub fn into_parts(self) -> EncoderReaderParts<R> {
EncoderReaderParts {
unread_input: self.input[self.head..self.end].to_vec(),
source: self.source,
}
}
fn fill(&mut self) -> Result<()> {
self.head = 0;
self.end = 0;
self.input.resize(FILL_CHUNK, 0);
loop {
match self.source.read(&mut self.input) {
Ok(0) => {
self.eof = true;
return Ok(());
}
Ok(n) => {
self.end = n.min(self.input.len());
return Ok(());
}
Err(error) if error.kind() == ErrorKind::Interrupted => {}
Err(error) => return Err(error),
}
}
}
}
impl<R: Read> Read for ParallelEncoderReader<'_, R> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
if buf.is_empty() || self.session.is_finished() {
return Ok(0);
}
loop {
if self.head == self.end && !self.eof {
self.fill()?;
}
let operation = if self.eof {
Operation::End
} else {
Operation::Continue
};
let progress =
self.session
.process(&self.input[self.head..self.end], buf, operation)?;
self.head += progress.consumed;
if progress.produced > 0 || progress.status == ParallelEncoderStatus::Finished {
return Ok(progress.produced);
}
if progress.status == ParallelEncoderStatus::Pending {
self.session.wait()?;
}
}
}
}