use super::super::{DecodeError, DecodeOperation, DecoderSession, DecoderStatus};
use std::io::{self, ErrorKind, Read};
#[derive(Debug)]
pub struct DecoderReader<'d, 'dict, R> {
session: DecoderSession<'d, 'dict>,
reader: R,
buffer: Vec<u8>,
cursor: usize,
filled: usize,
eof: bool,
pending_error: Option<io::Error>,
failed: bool,
}
#[derive(Debug)]
pub struct DecoderReaderParts<R> {
pub reader: R,
pub unread_input: Vec<u8>,
pub finished: bool,
pub pending_error: Option<io::Error>,
}
impl<'d, 'dict, R: Read> DecoderReader<'d, 'dict, R> {
pub(super) fn new(session: DecoderSession<'d, 'dict>, reader: R) -> Result<Self, DecodeError> {
Ok(Self {
session,
reader,
buffer: super::buffer()?,
cursor: 0,
filled: 0,
eof: false,
pending_error: None,
failed: false,
})
}
pub const fn get_ref(&self) -> &R {
&self.reader
}
pub const fn get_mut(&mut self) -> &mut R {
&mut self.reader
}
pub const fn is_finished(&self) -> bool {
self.session.is_finished() && !self.failed
}
pub fn into_parts(mut self) -> DecoderReaderParts<R> {
let finished = self.is_finished();
self.buffer.truncate(self.filled);
self.buffer.drain(..self.cursor);
DecoderReaderParts {
reader: self.reader,
unread_input: self.buffer,
finished,
pending_error: self.pending_error,
}
}
}
impl<R: Read> Read for DecoderReader<'_, '_, R> {
fn read(&mut self, output: &mut [u8]) -> io::Result<usize> {
if output.is_empty() {
return Ok(0);
}
if let Some(error) = self.pending_error.take() {
return Err(error);
}
if self.failed {
return Err(DecodeError::InvalidState.into());
}
loop {
let operation = if self.eof {
DecodeOperation::Finish
} else {
DecodeOperation::Process
};
match self
.session
.process(&self.buffer[self.cursor..self.filled], output, operation)
{
Ok(progress) => {
self.cursor += progress.consumed;
if progress.produced != 0 || progress.status == DecoderStatus::Finished {
return Ok(progress.produced);
}
}
Err(failure) => {
self.cursor += failure.consumed;
self.failed = true;
let error = failure.error.into();
if failure.produced == 0 {
return Err(error);
}
self.pending_error = Some(error);
return Ok(failure.produced);
}
}
loop {
match self.reader.read(&mut self.buffer) {
Err(error) if error.kind() == ErrorKind::Interrupted => continue,
Err(error) => return Err(error),
Ok(length) => {
self.cursor = 0;
self.filled = length;
self.eof = length == 0;
break;
}
}
}
}
}
}