use ::core::mem::MaybeUninit;
use super::core::{DictView, Stream};
use super::{DecodeError, Decompressor};
use crate::dictionary::{DecodeDictionary, DictionaryRef};
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub enum DecodeOperation {
#[default]
Process,
Finish,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum DecoderStatus {
NeedsInput,
NeedsOutput,
Finished,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct DecodeProgress {
pub consumed: usize,
pub produced: usize,
pub status: DecoderStatus,
}
#[derive(Debug, thiserror::Error)]
#[error("{error}")]
pub struct DecodeFailure {
#[source]
pub error: DecodeError,
pub consumed: usize,
pub produced: usize,
}
impl DecodeFailure {
#[must_use]
pub fn into_error(self) -> DecodeError {
self.error
}
}
impl From<DecodeFailure> for DecodeError {
fn from(failure: DecodeFailure) -> Self {
failure.error
}
}
#[derive(Debug)]
pub struct DecoderSession<'d> {
decoder: &'d mut Decompressor,
dictionary: Option<DictView<'d>>,
}
impl<'d> DecoderSession<'d> {
pub(super) fn new(decoder: &'d mut Decompressor, dictionary: Option<DictView<'d>>) -> Self {
decoder.apply_retention();
let config = decoder.config;
decoder.stream.reset(config);
Self {
decoder,
dictionary,
}
}
}
fn dictionary_view<D: AsRef<DecodeDictionary>>(dictionary: Option<&D>) -> Option<DictView<'_>> {
dictionary.map(|dictionary| DictionaryRef::from(dictionary.as_ref()).view())
}
fn process_on(
decoder: &mut Decompressor,
call: impl FnOnce(&mut Stream) -> Result<DecodeProgress, DecodeFailure>,
) -> Result<DecodeProgress, DecodeFailure> {
let result = call(&mut decoder.stream);
if result
.as_ref()
.map_or(true, |progress| progress.status == DecoderStatus::Finished)
{
decoder.apply_retention();
}
result
}
impl DecoderSession<'_> {
pub fn process(
&mut self,
input: &[u8],
output: &mut [u8],
operation: DecodeOperation,
) -> Result<DecodeProgress, DecodeFailure> {
let dictionary = self.dictionary;
process_on(self.decoder, |stream| {
stream.process(input, output, operation, dictionary)
})
}
pub fn process_uninit(
&mut self,
input: &[u8],
output: &mut [MaybeUninit<u8>],
operation: DecodeOperation,
) -> Result<DecodeProgress, DecodeFailure> {
let dictionary = self.dictionary;
process_on(self.decoder, |stream| {
stream.process_uninit(input, output, operation, dictionary)
})
}
pub fn flush(&mut self, output: &mut [u8]) -> Result<DecodeProgress, DecodeFailure> {
self.process(&[], output, DecodeOperation::Process)
}
pub fn finish(&mut self, output: &mut [u8]) -> Result<DecodeProgress, DecodeFailure> {
self.process(&[], output, DecodeOperation::Finish)
}
#[must_use]
pub fn is_finished(&self) -> bool {
self.decoder.stream.is_finished()
}
#[must_use]
pub fn total_in(&self) -> u64 {
self.decoder.stream.total_in()
}
#[must_use]
pub fn total_out(&self) -> u64 {
self.decoder.stream.total_out()
}
#[must_use]
pub fn frames_decoded(&self) -> u64 {
self.decoder.stream.frames_decoded()
}
#[must_use]
pub fn window_size(&self) -> Option<u64> {
self.decoder.stream.window_size()
}
}
#[derive(Debug)]
pub struct DecoderSessionOwned<D = DecodeDictionary> {
decoder: Decompressor,
dictionary: Option<D>,
}
impl<D: AsRef<DecodeDictionary>> DecoderSessionOwned<D> {
pub(super) fn new(mut decoder: Decompressor, dictionary: Option<D>) -> Self {
decoder.apply_retention();
let config = decoder.config;
decoder.stream.reset(config);
Self {
decoder,
dictionary,
}
}
pub fn process(
&mut self,
input: &[u8],
output: &mut [u8],
operation: DecodeOperation,
) -> Result<DecodeProgress, DecodeFailure> {
let dictionary = dictionary_view(self.dictionary.as_ref());
process_on(&mut self.decoder, |stream| {
stream.process(input, output, operation, dictionary)
})
}
pub fn process_uninit(
&mut self,
input: &[u8],
output: &mut [MaybeUninit<u8>],
operation: DecodeOperation,
) -> Result<DecodeProgress, DecodeFailure> {
let dictionary = dictionary_view(self.dictionary.as_ref());
process_on(&mut self.decoder, |stream| {
stream.process_uninit(input, output, operation, dictionary)
})
}
pub fn flush(&mut self, output: &mut [u8]) -> Result<DecodeProgress, DecodeFailure> {
self.process(&[], output, DecodeOperation::Process)
}
pub fn finish(&mut self, output: &mut [u8]) -> Result<DecodeProgress, DecodeFailure> {
self.process(&[], output, DecodeOperation::Finish)
}
#[must_use]
pub fn is_finished(&self) -> bool {
self.decoder.stream.is_finished()
}
#[must_use]
pub fn total_in(&self) -> u64 {
self.decoder.stream.total_in()
}
#[must_use]
pub fn total_out(&self) -> u64 {
self.decoder.stream.total_out()
}
#[must_use]
pub fn frames_decoded(&self) -> u64 {
self.decoder.stream.frames_decoded()
}
#[must_use]
pub fn window_size(&self) -> Option<u64> {
self.decoder.stream.window_size()
}
pub fn reinit(&mut self) {
self.decoder.apply_retention();
let config = self.decoder.config;
self.decoder.stream.reset(config);
}
#[must_use]
pub fn into_decompressor(mut self) -> Decompressor {
self.decoder.apply_retention();
self.decoder
}
}