use crate::{Compression, Error, Result};
#[allow(clippy::large_enum_variant)]
pub(crate) enum CompressionState {
None,
#[cfg(feature = "lz4")]
Lz4(Lz4),
}
impl CompressionState {
pub(crate) fn new(parameters: Compression) -> Result<Self> {
match parameters {
Compression::None => Ok(Self::None),
#[cfg(feature = "lz4")]
Compression::Lz4 => Ok(Self::Lz4(Lz4::new())),
#[cfg(not(feature = "lz4"))]
Compression::Lz4 => Err(Error::CompressionUnavailable),
}
}
pub(crate) fn encode(&mut self, _buffer: &mut Vec<u8>) -> Result<()> {
match self {
Self::None => Ok(()),
#[cfg(feature = "lz4")]
Self::Lz4(codec) => codec.encode(_buffer),
}
}
pub(crate) fn decode(&mut self, _buffer: &mut Vec<u8>, _raw_len: usize) -> Result<()> {
match self {
Self::None => Err(Error::DecompressionFailed),
#[cfg(feature = "lz4")]
Self::Lz4(codec) => codec.decode(_buffer, _raw_len),
}
}
}
#[cfg(feature = "lz4")]
#[derive(Default)]
pub(crate) struct Lz4 {
scratch: Vec<u8>,
table: Option<lz4_flex::block::CompressTable>,
}
#[cfg(feature = "lz4")]
impl Lz4 {
pub(crate) fn new() -> Self {
Self::default()
}
}
#[cfg(feature = "lz4")]
impl Lz4 {
fn encode(&mut self, buffer: &mut Vec<u8>) -> Result<()> {
use lz4_flex::block::{CompressTable, compress_into_with_table, get_maximum_output_size};
crate::error::resize(&mut self.scratch, get_maximum_output_size(buffer.len()))?;
let table = self.table.get_or_insert_with(CompressTable::large);
let written = compress_into_with_table(buffer, &mut self.scratch, table)
.map_err(|_| crate::Error::CompressionFailed)?;
if written < buffer.len() {
self.scratch.truncate(written);
std::mem::swap(buffer, &mut self.scratch);
}
Ok(())
}
fn decode(&mut self, buffer: &mut Vec<u8>, raw_len: usize) -> Result<()> {
crate::error::resize(&mut self.scratch, raw_len)?;
let written = lz4_flex::block::decompress_into(buffer, &mut self.scratch)
.map_err(|_| crate::Error::DecompressionFailed)?;
if written != raw_len {
return Err(crate::Error::DecompressionFailed);
}
std::mem::swap(buffer, &mut self.scratch);
Ok(())
}
}