use alloc::vec;
use core::mem::MaybeUninit;
use super::core::error::CoreError;
use super::core::stream::EndOp;
use super::encoder::Compressor;
use super::error::EncodeError;
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Hash)]
pub enum InputSize {
#[default]
Unknown,
Exact(u64),
}
impl From<u64> for InputSize {
fn from(value: u64) -> Self {
Self::Exact(value)
}
}
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Hash)]
pub struct StreamConfig {
input_size: InputSize,
}
impl StreamConfig {
#[must_use]
pub const fn with_input_size(mut self, input_size: InputSize) -> Self {
self.input_size = input_size;
self
}
#[must_use]
pub const fn input_size(&self) -> InputSize {
self.input_size
}
}
impl From<InputSize> for StreamConfig {
fn from(input_size: InputSize) -> Self {
Self { input_size }
}
}
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Hash)]
pub enum Operation {
#[default]
Continue,
Flush,
End,
}
impl Operation {
const fn to_core(self) -> EndOp {
match self {
Self::Continue => EndOp::Continue,
Self::Flush => EndOp::Flush,
Self::End => EndOp::End,
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum EncoderStatus {
NeedsInput,
NeedsOutput,
Finished,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct Progress {
pub consumed: usize,
pub produced: usize,
pub status: EncoderStatus,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
enum State {
Open,
Finished,
Failed,
}
#[derive(Debug)]
struct Core {
state: State,
declared: Option<u64>,
}
impl Core {
fn new(stream: StreamConfig) -> Self {
Self {
state: State::Open,
declared: match stream.input_size() {
InputSize::Exact(size) => Some(size),
InputSize::Unknown => None,
},
}
}
fn process(
&mut self,
compressor: &mut Compressor,
input: &[u8],
output: &mut [u8],
operation: Operation,
) -> Result<Progress, EncodeError> {
match self.state {
State::Failed => return Err(EncodeError::InvalidState),
State::Finished => {
return Ok(Progress {
consumed: 0,
produced: 0,
status: EncoderStatus::Finished,
});
}
State::Open => {}
}
let result = compressor.stream.compress(
&mut compressor.engine,
&compressor.requested,
output,
input,
operation.to_core(),
);
let step = match result {
Ok(step) => step,
Err(error) => {
self.state = State::Failed;
return Err(match error {
CoreError::DstSizeTooSmall => EncodeError::Internal,
other => EncodeError::from_core(other, output.len(), self.declared),
});
}
};
let status =
if operation == Operation::End && step.remaining == 0 && compressor.stream.is_idle() {
self.state = State::Finished;
compressor.apply_retention();
EncoderStatus::Finished
} else if step.remaining > 0 {
EncoderStatus::NeedsOutput
} else {
EncoderStatus::NeedsInput
};
Ok(Progress {
consumed: step.consumed,
produced: step.produced,
status,
})
}
fn process_uninit(
&mut self,
compressor: &mut Compressor,
input: &[u8],
output: &mut [MaybeUninit<u8>],
operation: Operation,
) -> Result<Progress, EncodeError> {
let mut scratch = vec![0u8; output.len()];
let progress = self.process(compressor, input, &mut scratch, operation)?;
for (slot, &byte) in output.iter_mut().zip(&scratch[..progress.produced]) {
slot.write(byte);
}
Ok(progress)
}
}
macro_rules! session_methods {
($compressor:ident) => {
pub fn process(
&mut self,
input: &[u8],
output: &mut [u8],
operation: Operation,
) -> Result<Progress, EncodeError> {
let compressor = &mut *self.$compressor;
self.core.process(compressor, input, output, operation)
}
pub fn process_uninit(
&mut self,
input: &[u8],
output: &mut [MaybeUninit<u8>],
operation: Operation,
) -> Result<Progress, EncodeError> {
let compressor = &mut *self.$compressor;
self.core
.process_uninit(compressor, input, output, operation)
}
pub fn flush(&mut self, output: &mut [u8]) -> Result<Progress, EncodeError> {
self.process(&[], output, Operation::Flush)
}
pub fn finish(&mut self, output: &mut [u8]) -> Result<Progress, EncodeError> {
self.process(&[], output, Operation::End)
}
#[must_use]
pub fn is_finished(&self) -> bool {
self.core.state == State::Finished
}
};
}
#[derive(Debug)]
pub struct EncoderSession<'c> {
compressor: &'c mut Compressor,
core: Core,
}
impl<'c> EncoderSession<'c> {
pub(crate) fn new(compressor: &'c mut Compressor, stream: StreamConfig) -> Self {
Self {
compressor,
core: Core::new(stream),
}
}
session_methods!(compressor);
}
#[derive(Debug)]
pub struct EncoderSessionOwned {
compressor: alloc::boxed::Box<Compressor>,
core: Core,
}
impl EncoderSessionOwned {
pub(crate) fn new(compressor: Compressor, stream: StreamConfig) -> Self {
Self {
compressor: alloc::boxed::Box::new(compressor),
core: Core::new(stream),
}
}
session_methods!(compressor);
pub fn reinit(&mut self, stream: StreamConfig) {
self.compressor.begin_stream(stream);
self.core = Core::new(stream);
}
#[must_use]
pub fn into_compressor(self) -> Compressor {
let mut compressor = *self.compressor;
compressor.stream.reset_session();
compressor
}
}