use super::{FramedError, FramingConfig, MetadataField, core};
use crate::graph::CompressorGraph;
use crate::input::Input;
use crate::{Compressor, EncoderConfig};
use ::core::ops::Range;
use alloc::vec::Vec;
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct FramedEncodeConfig {
pub encoder: EncoderConfig,
pub framing: FramingConfig,
}
#[derive(Clone, Copy, Debug)]
pub enum ResourceInput<'a> {
Serial(&'a [u8]),
Typed(&'a [Input<'a>]),
}
#[derive(Clone, Copy, Debug)]
pub struct FramedResource<'a> {
pub input: ResourceInput<'a>,
pub graph: Option<&'a CompressorGraph>,
pub metadata: &'a [MetadataField<'a>],
}
impl<'a> From<&'a [u8]> for FramedResource<'a> {
fn from(bytes: &'a [u8]) -> Self {
Self {
input: ResourceInput::Serial(bytes),
graph: None,
metadata: &[],
}
}
}
impl<'a> From<&'a [Input<'a>]> for FramedResource<'a> {
fn from(inputs: &'a [Input<'a>]) -> Self {
Self {
input: ResourceInput::Typed(inputs),
graph: None,
metadata: &[],
}
}
}
#[derive(Clone, Copy, Debug)]
pub struct FramedInput<'a> {
pub resources: &'a [FramedResource<'a>],
}
impl<'a> From<&'a [FramedResource<'a>]> for FramedInput<'a> {
fn from(resources: &'a [FramedResource<'a>]) -> Self {
Self { resources }
}
}
#[derive(Debug)]
pub struct FramedCompressor {
pub(super) raw: Compressor,
pub(super) config: FramingConfig,
}
impl From<Compressor> for FramedCompressor {
fn from(raw: Compressor) -> Self {
Self {
raw,
config: FramingConfig::default(),
}
}
}
impl FramedCompressor {
pub fn new(config: FramedEncodeConfig) -> Result<Self, FramedError> {
core::validate(config.framing)?;
Ok(Self {
raw: Compressor::new(config.encoder)?,
config: config.framing,
})
}
pub fn reconfigure(&mut self, config: FramingConfig) -> Result<(), FramedError> {
core::validate(config)?;
self.config = config;
Ok(())
}
pub fn start(&mut self) -> Result<FramedEncoderSession<'_>, FramedError> {
Ok(FramedEncoderSession {
owner: self,
state: core::encode::Encoder::start()?,
})
}
pub fn compress(&mut self, input: FramedInput<'_>) -> Result<Vec<u8>, FramedError> {
let mut dst = Vec::new();
self.compress_into(input, &mut dst)?;
Ok(dst)
}
pub fn compress_into(
&mut self,
input: FramedInput<'_>,
dst: &mut Vec<u8>,
) -> Result<Range<usize>, FramedError> {
let start = dst.len();
let result = (|| {
let mut session = self.start()?;
session.append(dst, FramedEncodeOperation::Process)?;
for &resource in input.resources {
session.resource(resource)?;
session.append(dst, FramedEncodeOperation::Process)?;
}
session.append(dst, FramedEncodeOperation::Finish)
})();
if let Err(error) = result {
dst.truncate(start);
return Err(error);
}
Ok(start..dst.len())
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum FramedEncodeOperation {
Process,
Finish,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum FramedEncoderStatus {
NeedsInput,
NeedsOutput,
Finished,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct FramedEncodeProgress {
pub produced: usize,
pub status: FramedEncoderStatus,
}
#[derive(Debug)]
pub struct FramedEncoderSession<'a> {
pub(super) owner: &'a mut FramedCompressor,
pub(super) state: core::encode::Encoder,
}
impl FramedEncoderSession<'_> {
pub fn resource(&mut self, resource: FramedResource<'_>) -> Result<(), FramedError> {
self.state
.resource(&mut self.owner.raw, self.owner.config, resource)
}
pub fn process(
&mut self,
output: &mut [u8],
operation: FramedEncodeOperation,
) -> Result<FramedEncodeProgress, FramedError> {
self.state
.process(&self.owner.raw, self.owner.config, output, operation)
}
fn append(&mut self, dst: &mut Vec<u8>, op: FramedEncodeOperation) -> Result<(), FramedError> {
let mut buffer = [0; 8192];
loop {
let progress = self.process(&mut buffer, op)?;
core::reserve(dst, progress.produced)?;
dst.extend_from_slice(&buffer[..progress.produced]);
if progress.status != FramedEncoderStatus::NeedsOutput {
return Ok(());
}
}
}
}