use super::{FramedError, FramingConfig, MetadataEntry, ResourceInfo, core};
use crate::{DecodeOperation, DecoderConfig, Decompressor, TypedOutput};
use alloc::vec::Vec;
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct FramedDecodeConfig {
pub decoder: DecoderConfig,
pub framing: FramingConfig,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct DecodedResource {
pub info: ResourceInfo,
pub metadata: Vec<MetadataEntry>,
pub outputs: Vec<TypedOutput>,
}
#[derive(Debug, Clone, Default, Eq, PartialEq)]
pub struct FramedOutput {
pub resources: Vec<DecodedResource>,
}
#[derive(Debug)]
pub struct FramedDecompressor {
pub(super) raw: Decompressor,
pub(super) config: FramingConfig,
}
impl From<Decompressor> for FramedDecompressor {
fn from(raw: Decompressor) -> Self {
Self {
raw,
config: FramingConfig::default(),
}
}
}
impl FramedDecompressor {
pub fn new(config: FramedDecodeConfig) -> Result<Self, FramedError> {
core::validate(config.framing)?;
Ok(Self {
raw: Decompressor::new(config.decoder),
config: config.framing,
})
}
pub fn reconfigure(&mut self, config: FramingConfig) -> Result<(), FramedError> {
core::validate(config)?;
self.config = config;
Ok(())
}
pub fn start(&mut self) -> FramedDecoderSession<'_> {
FramedDecoderSession {
owner: self,
state: core::decode::Decoder::default(),
}
}
pub fn decompress(&mut self, src: &[u8]) -> Result<FramedOutput, FramedError> {
let mut session = self.start();
let mut at = 0;
let mut resources = Vec::new();
loop {
let progress = session
.process(&src[at..], DecodeOperation::Finish)
.map_err(|failure| failure.error)?;
at += progress.consumed;
if let Some(resource) = progress.resource {
core::reserve(&mut resources, 1)?;
resources.push(resource);
}
if progress.status == FramedDecoderStatus::Finished {
return Ok(FramedOutput { resources });
}
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum FramedDecoderStatus {
NeedsInput,
Resource,
Finished,
}
#[derive(Debug)]
pub struct FramedDecodeProgress {
pub consumed: usize,
pub resource: Option<DecodedResource>,
pub status: FramedDecoderStatus,
}
#[derive(Debug, thiserror::Error)]
#[error("{error}")]
pub struct FramedDecodeFailure {
#[source]
pub error: FramedError,
pub consumed: usize,
}
#[derive(Debug)]
pub struct FramedDecoderSession<'a> {
pub(super) owner: &'a mut FramedDecompressor,
pub(super) state: core::decode::Decoder,
}
impl FramedDecoderSession<'_> {
pub fn process(
&mut self,
input: &[u8],
operation: DecodeOperation,
) -> Result<FramedDecodeProgress, FramedDecodeFailure> {
let before = self.state.accepted;
self.state
.process(&mut self.owner.raw, self.owner.config, input, operation)
.map_err(|error| FramedDecodeFailure {
error,
consumed: (self.state.accepted - before) as usize,
})
}
}