use super::*;
use crate::dictionary::PreparedDictionary;
use crate::{Operation, StreamConfig};
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub enum FramedEncodeOperation {
#[default]
Process,
Finish,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum FramedEncoderStatus {
NeedsInput,
NeedsOutput,
Finished,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct FramedEncodeProgress {
pub consumed: usize,
pub produced: usize,
pub status: FramedEncoderStatus,
}
#[derive(Debug)]
pub struct FramedEncoderSession<'c> {
pub(super) owner: &'c mut FramedCompressor,
}
impl FramedEncoderSession<'_> {
pub fn process(
&mut self,
output: &mut [u8],
operation: FramedEncodeOperation,
) -> Result<FramedEncodeProgress, FramedEncodeFailure> {
self.owner.engine.process(output, operation)
}
pub fn flush(
&mut self,
output: &mut [u8],
) -> Result<FramedEncodeProgress, FramedEncodeFailure> {
self.process(output, FramedEncodeOperation::Process)
}
pub fn finish(
&mut self,
output: &mut [u8],
) -> Result<FramedEncodeProgress, FramedEncodeFailure> {
self.process(output, FramedEncodeOperation::Finish)
}
pub fn metadata(
&mut self,
kind: MetadataKind,
fields: &[MetadataField<'_>],
) -> Result<(), FramedEncodeError> {
self.metadata_with_options(kind, fields, MetadataOptions::default())
}
pub fn metadata_with_options(
&mut self,
kind: MetadataKind,
fields: &[MetadataField<'_>],
options: MetadataOptions<'_>,
) -> Result<(), FramedEncodeError> {
self.owner.session_metadata(kind, fields, options)
}
pub fn repeat_metadata_fields(&mut self, codes: &[[u8; 2]]) -> Result<(), FramedEncodeError> {
self.owner.engine.repeat(codes)
}
pub fn padding(&mut self, bytes: usize) -> Result<(), FramedEncodeError> {
self.owner.engine.padding(bytes)
}
pub fn resource(
&mut self,
options: ResourceOptions,
stream: StreamConfig,
) -> Result<FramedResourceSession<'_, 'static>, FramedEncodeError> {
self.owner
.open_resource(options, stream, ResourceEncoding::Zstd, None)
}
pub fn resource_with_dictionary<'s, 'dict>(
&'s mut self,
options: ResourceOptions,
stream: StreamConfig,
dictionary: &'dict PreparedDictionary,
references: &[DictionaryReference],
) -> Result<FramedResourceSession<'s, 'dict>, FramedEncodeError> {
self.owner
.open_shared_resource(options, stream, dictionary, references)
}
pub fn uncompressed_resource(
&mut self,
options: ResourceOptions,
) -> Result<FramedResourceSession<'_, 'static>, FramedEncodeError> {
self.owner.open_resource(
options,
StreamConfig::default(),
ResourceEncoding::Uncompressed,
None,
)
}
#[must_use]
pub const fn total_in(&self) -> u64 {
self.owner.engine.total_in
}
#[must_use]
pub const fn total_out(&self) -> u64 {
self.owner.engine.total_out
}
#[must_use]
pub const fn resources_encoded(&self) -> u64 {
self.owner.engine.resources()
}
#[must_use]
pub const fn is_finished(&self) -> bool {
self.owner.engine.finished()
}
#[must_use]
pub const fn next_chunk_offset(&self) -> u64 {
self.owner.engine.offset()
}
}
impl Drop for FramedEncoderSession<'_> {
fn drop(&mut self) {
self.owner.cancel();
}
}
impl FramedCompressor {
fn session_metadata(
&mut self,
kind: MetadataKind,
fields: &[MetadataField<'_>],
options: MetadataOptions<'_>,
) -> Result<(), FramedEncodeError> {
self.engine.metadata(&mut self.raw, kind, fields, options)
}
fn open_resource<'s, 'dict>(
&'s mut self,
options: ResourceOptions,
stream: StreamConfig,
encoding: ResourceEncoding<'_>,
dictionary: Option<&'dict PreparedDictionary>,
) -> Result<FramedResourceSession<'s, 'dict>, FramedEncodeError> {
self.engine
.begin_resource(&self.raw, options, stream, encoding)?;
Ok(FramedResourceSession {
owner: self,
dictionary,
})
}
fn open_shared_resource<'s, 'dict>(
&'s mut self,
options: ResourceOptions,
stream: StreamConfig,
dictionary: &'dict PreparedDictionary,
references: &[DictionaryReference],
) -> Result<FramedResourceSession<'s, 'dict>, FramedEncodeError> {
let encoding = ResourceEncoding::Shared {
dictionary,
references,
};
self.open_resource(options, stream, encoding, Some(dictionary))
}
}
#[derive(Debug)]
pub struct FramedEncoderSessionOwned {
pub(super) owner: FramedCompressor,
}
impl FramedEncoderSessionOwned {
pub fn process(
&mut self,
output: &mut [u8],
operation: FramedEncodeOperation,
) -> Result<FramedEncodeProgress, FramedEncodeFailure> {
self.owner.engine.process(output, operation)
}
pub fn flush(
&mut self,
output: &mut [u8],
) -> Result<FramedEncodeProgress, FramedEncodeFailure> {
self.process(output, FramedEncodeOperation::Process)
}
pub fn finish(
&mut self,
output: &mut [u8],
) -> Result<FramedEncodeProgress, FramedEncodeFailure> {
self.process(output, FramedEncodeOperation::Finish)
}
pub fn metadata(
&mut self,
kind: MetadataKind,
fields: &[MetadataField<'_>],
) -> Result<(), FramedEncodeError> {
self.owner
.session_metadata(kind, fields, MetadataOptions::default())
}
pub fn metadata_with_options(
&mut self,
kind: MetadataKind,
fields: &[MetadataField<'_>],
options: MetadataOptions<'_>,
) -> Result<(), FramedEncodeError> {
self.owner.session_metadata(kind, fields, options)
}
pub fn repeat_metadata_fields(&mut self, codes: &[[u8; 2]]) -> Result<(), FramedEncodeError> {
self.owner.engine.repeat(codes)
}
pub fn padding(&mut self, bytes: usize) -> Result<(), FramedEncodeError> {
self.owner.engine.padding(bytes)
}
pub fn resource(
&mut self,
options: ResourceOptions,
stream: StreamConfig,
) -> Result<FramedResourceSession<'_, 'static>, FramedEncodeError> {
self.owner
.open_resource(options, stream, ResourceEncoding::Zstd, None)
}
pub fn resource_with_dictionary<'s, 'dict>(
&'s mut self,
options: ResourceOptions,
stream: StreamConfig,
dictionary: &'dict PreparedDictionary,
references: &[DictionaryReference],
) -> Result<FramedResourceSession<'s, 'dict>, FramedEncodeError> {
self.owner
.open_shared_resource(options, stream, dictionary, references)
}
pub fn uncompressed_resource(
&mut self,
options: ResourceOptions,
) -> Result<FramedResourceSession<'_, 'static>, FramedEncodeError> {
self.owner.open_resource(
options,
StreamConfig::default(),
ResourceEncoding::Uncompressed,
None,
)
}
#[must_use]
pub const fn total_in(&self) -> u64 {
self.owner.engine.total_in
}
#[must_use]
pub const fn total_out(&self) -> u64 {
self.owner.engine.total_out
}
#[must_use]
pub const fn resources_encoded(&self) -> u64 {
self.owner.engine.resources()
}
#[must_use]
pub const fn is_finished(&self) -> bool {
self.owner.engine.finished()
}
#[must_use]
pub const fn next_chunk_offset(&self) -> u64 {
self.owner.engine.offset()
}
pub fn reinit(&mut self, stream: FramedEncodeStreamConfig) -> Result<(), FramedEncodeError> {
self.owner.cancel();
let started = self.owner.begin_session(stream);
if started.is_err() {
self.owner.engine.poison();
}
started
}
#[must_use]
pub fn into_framed_compressor(self) -> FramedCompressor {
let Self { mut owner } = self;
owner.cancel();
owner
}
}
#[derive(Debug)]
pub struct FramedResourceSession<'session, 'dict> {
pub(super) owner: &'session mut FramedCompressor,
dictionary: Option<&'dict PreparedDictionary>,
}
impl FramedResourceSession<'_, '_> {
pub fn process(
&mut self,
input: &[u8],
output: &mut [u8],
operation: Operation,
) -> Result<FramedEncodeProgress, FramedEncodeFailure> {
self.owner.engine.process_resource(
&mut self.owner.raw,
self.dictionary,
input,
output,
operation,
)
}
pub fn flush(
&mut self,
output: &mut [u8],
) -> Result<FramedEncodeProgress, FramedEncodeFailure> {
self.process(&[], output, Operation::Flush)
}
pub fn finish(
&mut self,
output: &mut [u8],
) -> Result<FramedEncodeProgress, FramedEncodeFailure> {
self.process(&[], output, Operation::End)
}
#[must_use]
pub const fn is_finished(&self) -> bool {
self.owner.engine.resource_finished()
}
#[must_use]
pub const fn total_in(&self) -> u64 {
self.owner.engine.resource_in()
}
#[must_use]
pub const fn total_out(&self) -> u64 {
self.owner.engine.resource_out()
}
}
impl Drop for FramedResourceSession<'_, '_> {
fn drop(&mut self) {
self.owner.engine.release_resource();
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_poisoned_owned_session_refuses_work_until_a_reinit_succeeds() {
let mut session = FramedCompressor::new(FramedEncodeConfig::default())
.expect("config")
.into_session(FramedEncodeStreamConfig::default())
.expect("start");
session.owner.cancel();
session.owner.engine.poison();
let failure = session
.process(&mut [0; 64], FramedEncodeOperation::Process)
.unwrap_err();
assert!(matches!(failure.error, FramedEncodeError::InvalidState));
assert!(matches!(
session.padding(1),
Err(FramedEncodeError::InvalidState)
));
assert!(matches!(
session.resource(ResourceOptions::default(), StreamConfig::default()),
Err(FramedEncodeError::InvalidState)
));
session
.reinit(FramedEncodeStreamConfig::default())
.expect("reinit");
let mut output = [0; 64];
let progress = session
.process(&mut output, FramedEncodeOperation::Process)
.expect("header");
assert_eq!(
&output[..progress.produced],
b"\x5b\x2a\x4d\x18\x05\0\0\0MZFR\x04"
);
}
}