use ::core::mem::MaybeUninit;
use ::core::ops::Range;
use alloc::vec::Vec;
use super::core::{DictView, Stream};
use super::{
DecodeError, DecodeFailure, DecodeOperation, DecodeProgress, DecoderConfig, DecoderSession,
DecoderSessionOwned, DecoderStatus,
};
use crate::dictionary::{DecodeDictionary, DictionaryRef};
use crate::{Backend, RetentionPolicy};
#[derive(Debug)]
pub struct Decompressor {
pub(super) config: DecoderConfig,
retention: RetentionPolicy,
pub(super) stream: Stream,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct DecompressorBuilder {
config: DecoderConfig,
retention: RetentionPolicy,
backend: Option<Backend>,
}
impl DecompressorBuilder {
#[must_use]
pub const fn with_retention(mut self, retention: RetentionPolicy) -> Self {
self.retention = retention;
self
}
#[must_use]
pub const fn with_backend(mut self, backend: Backend) -> Self {
self.backend = Some(backend);
self
}
#[must_use]
pub fn build(self) -> Decompressor {
Decompressor {
config: self.config,
retention: self.retention,
stream: Stream::new(self.config, self.backend.unwrap_or_default()),
}
}
}
impl Default for Decompressor {
fn default() -> Self {
Self::new(DecoderConfig::DEFAULT)
}
}
impl From<DecoderConfig> for Decompressor {
fn from(config: DecoderConfig) -> Self {
Self::new(config)
}
}
impl Decompressor {
#[must_use]
pub fn new(config: DecoderConfig) -> Self {
Self::builder(config).build()
}
#[must_use]
pub const fn builder(config: DecoderConfig) -> DecompressorBuilder {
DecompressorBuilder {
config,
retention: RetentionPolicy::Aggressive,
backend: None,
}
}
#[must_use]
pub const fn backend(&self) -> Backend {
self.stream.backend()
}
#[must_use]
pub const fn config(&self) -> &DecoderConfig {
&self.config
}
#[must_use]
pub const fn retention(&self) -> RetentionPolicy {
self.retention
}
pub fn reconfigure(&mut self, config: DecoderConfig) {
self.config = config;
self.stream.reset(config);
}
#[must_use]
pub fn retained_bytes(&self) -> usize {
self.stream.retained_bytes()
}
pub fn trim(&mut self, policy: RetentionPolicy) {
if !policy.allows(self.retained_bytes()) {
self.stream.release();
}
}
pub(super) fn apply_retention(&mut self) {
self.trim(self.retention);
}
pub fn start(&mut self) -> DecoderSession<'_> {
DecoderSession::new(self, None)
}
pub fn start_with_dictionary<'d>(
&'d mut self,
dictionary: impl Into<DictionaryRef<'d>>,
) -> DecoderSession<'d> {
DecoderSession::new(self, Some(dictionary.into().view()))
}
#[must_use]
pub fn into_session(self) -> DecoderSessionOwned {
DecoderSessionOwned::new(self, None)
}
#[must_use]
pub fn into_session_with_dictionary<D: AsRef<DecodeDictionary> + 'static>(
self,
dictionary: D,
) -> DecoderSessionOwned<D> {
DecoderSessionOwned::new(self, Some(dictionary))
}
pub fn decompress(&mut self, src: &[u8]) -> Result<Vec<u8>, DecodeError> {
let mut dst = Vec::new();
self.decompress_into(src, &mut dst)?;
Ok(dst)
}
pub fn decompress_into(
&mut self,
src: &[u8],
dst: &mut Vec<u8>,
) -> Result<Range<usize>, DecodeError> {
self.decode_into(src, dst, None)
}
fn decode_into(
&mut self,
src: &[u8],
dst: &mut Vec<u8>,
dictionary: Option<DictView<'_>>,
) -> Result<Range<usize>, DecodeError> {
let start = dst.len();
self.stream.reset(self.config);
let result = self.stream.decode_all(src, dst, dictionary);
self.apply_retention();
match result {
Ok(()) => Ok(start..dst.len()),
Err(error) => {
dst.truncate(start);
Err(error)
}
}
}
pub fn decompress_to_slice(
&mut self,
src: &[u8],
dst: &mut [u8],
) -> Result<usize, DecodeError> {
self.decode_to_slice(src, dst, None)
}
fn decode_to_slice(
&mut self,
src: &[u8],
dst: &mut [u8],
dictionary: Option<DictView<'_>>,
) -> Result<usize, DecodeError> {
self.stream.reset(self.config);
let direct = self.stream.decode_to_slice(src, dst, dictionary);
if let Some(written) = direct {
self.apply_retention();
return Ok(written);
}
let mut session = DecoderSession::new(self, dictionary);
one_shot_outcome(
session.process(src, dst, DecodeOperation::Finish),
src.len(),
)
}
pub fn decompress_to_uninit(
&mut self,
src: &[u8],
dst: &mut [MaybeUninit<u8>],
) -> Result<usize, DecodeError> {
self.decode_to_uninit(src, dst, None)
}
fn decode_to_uninit(
&mut self,
src: &[u8],
dst: &mut [MaybeUninit<u8>],
dictionary: Option<DictView<'_>>,
) -> Result<usize, DecodeError> {
self.stream.reset(self.config);
let direct = self.stream.decode_to_uninit(src, dst, dictionary);
if let Some(written) = direct {
self.apply_retention();
return Ok(written);
}
let mut session = DecoderSession::new(self, dictionary);
one_shot_outcome(
session.process_uninit(src, dst, DecodeOperation::Finish),
src.len(),
)
}
pub fn decompress_with_dictionary<'dict>(
&mut self,
dictionary: impl Into<DictionaryRef<'dict>>,
src: &[u8],
) -> Result<Vec<u8>, DecodeError> {
let mut dst = Vec::new();
self.decode_into(src, &mut dst, Some(dictionary.into().view()))?;
Ok(dst)
}
pub fn decompress_with_dictionary_into<'dict>(
&mut self,
dictionary: impl Into<DictionaryRef<'dict>>,
src: &[u8],
dst: &mut Vec<u8>,
) -> Result<Range<usize>, DecodeError> {
self.decode_into(src, dst, Some(dictionary.into().view()))
}
pub fn decompress_with_dictionary_to_slice<'dict>(
&mut self,
dictionary: impl Into<DictionaryRef<'dict>>,
src: &[u8],
dst: &mut [u8],
) -> Result<usize, DecodeError> {
self.decode_to_slice(src, dst, Some(dictionary.into().view()))
}
pub fn decompress_with_dictionary_to_uninit<'dict>(
&mut self,
dictionary: impl Into<DictionaryRef<'dict>>,
src: &[u8],
dst: &mut [MaybeUninit<u8>],
) -> Result<usize, DecodeError> {
self.decode_to_uninit(src, dst, Some(dictionary.into().view()))
}
}
fn one_shot_outcome(
result: Result<DecodeProgress, DecodeFailure>,
input_len: usize,
) -> Result<usize, DecodeError> {
let progress = result?;
match progress.status {
DecoderStatus::NeedsOutput => Err(DecodeError::OutputTooSmall {
written: progress.produced,
}),
DecoderStatus::NeedsInput => Err(DecodeError::UnexpectedEndOfInput),
DecoderStatus::Finished if progress.consumed != input_len => {
Err(DecodeError::TrailingData {
offset: progress.consumed as u64,
})
}
DecoderStatus::Finished => Ok(progress.produced),
}
}