use ::core::ops::Range;
use alloc::vec::Vec;
use super::core::Stream;
use super::{
DecodeError, DecodeOperation, DecoderConfig, DecoderSession, DecoderSessionOwned, DecoderStatus,
};
use crate::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,
}
impl DecompressorBuilder {
#[must_use]
pub const fn with_retention(mut self, retention: RetentionPolicy) -> Self {
self.retention = retention;
self
}
#[must_use]
pub fn build(self) -> Decompressor {
Decompressor {
config: self.config,
retention: self.retention,
stream: Stream::new(self.config),
}
}
}
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,
}
}
#[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)
}
#[must_use]
pub fn into_session(self) -> DecoderSessionOwned {
DecoderSessionOwned::new(self)
}
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> {
let start = dst.len();
self.stream.reset(self.config);
let result = self.stream.decode_all(src, dst);
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> {
let mut session = self.start();
let progress = session.process(src, dst, DecodeOperation::Finish)?;
match progress.status {
DecoderStatus::NeedsOutput => Err(DecodeError::OutputTooSmall {
written: progress.produced,
}),
DecoderStatus::NeedsInput => Err(DecodeError::UnexpectedEndOfInput),
DecoderStatus::Finished if progress.consumed != src.len() => {
Err(DecodeError::TrailingData {
offset: progress.consumed as u64,
})
}
DecoderStatus::Finished => Ok(progress.produced),
}
}
}