use crate::codec::brotli::DEFAULT_QUALITY;
use crate::codec::CODEC_FSST_BROTLI;
use crate::codec::{brotli, Codec};
use crate::error::CoreError;
pub struct FsstBrotliCodec;
impl Codec for FsstBrotliCodec {
fn id(&self) -> u8 {
CODEC_FSST_BROTLI
}
fn name(&self) -> &'static str {
"fsst+brotli"
}
fn min_compress_size(&self) -> usize {
256
}
fn compress(&self, plaintext: &[u8]) -> Result<Vec<u8>, CoreError> {
compress_with_baseline(plaintext, None)
}
fn decompress(&self, compressed: &[u8], _expected_len: u32) -> Result<Vec<u8>, CoreError> {
if compressed.len() < 4 {
return Err(CoreError::Corrupt {
reason: "fsst+brotli: truncated header".into(),
});
}
let mut len_bytes = [0u8; 4];
len_bytes.copy_from_slice(&compressed[..4]);
let fsst_len = u32::from_le_bytes(len_bytes) as usize;
if fsst_len == 0 {
let brotli_bytes = &compressed[4..];
return brotli::decompress_at_quality(brotli_bytes, _expected_len);
}
if 4 + fsst_len > compressed.len() {
return Err(CoreError::Corrupt {
reason: format!(
"fsst+brotli: fsst_len {fsst_len} overruns buffer {}",
compressed.len()
),
});
}
let _fsst_bytes = &compressed[4..4 + fsst_len];
let brotli_bytes = &compressed[4 + fsst_len..];
let fsst_escaped = brotli::decompress_at_quality(brotli_bytes, u32::MAX)?;
let plaintext = omnizip_fsst::decompress(&fsst_escaped).map_err(fsst_err)?;
Ok(plaintext)
}
}
fn pack_no_fsst(brotli_bytes: &[u8]) -> Vec<u8> {
let mut out = Vec::with_capacity(4 + brotli_bytes.len());
out.extend_from_slice(&0u32.to_le_bytes());
out.extend_from_slice(brotli_bytes);
out
}
fn fsst_err(e: omnizip_codecs::OmnizipError) -> CoreError {
CoreError::Corrupt {
reason: format!("fsst: {e}"),
}
}
pub fn compress_with_baseline(
plaintext: &[u8],
baseline: Option<&[u8]>,
) -> Result<Vec<u8>, CoreError> {
let owned_baseline: Option<Vec<u8>>;
let plain_brotli: &[u8] = match baseline {
Some(b) => b,
None => {
let c = crate::codec::codec_call(|| brotli::compress(plaintext, DEFAULT_QUALITY))?;
owned_baseline = Some(c);
owned_baseline.as_deref().unwrap_or_default()
}
};
if plaintext.len() < 1024 {
return Ok(pack_no_fsst(plain_brotli));
}
let fsst_compressed =
crate::codec::codec_call(|| omnizip_fsst::compress(plaintext).map_err(fsst_err))?;
let brotli_input = &fsst_compressed[..];
let brotli_compressed =
crate::codec::codec_call(|| brotli::compress(brotli_input, DEFAULT_QUALITY))?;
let composite_len = 4 + brotli_compressed.len() + fsst_compressed.len();
if composite_len >= plain_brotli.len() {
return Ok(pack_no_fsst(plain_brotli));
}
let mut out = Vec::with_capacity(composite_len);
let fsst_len = u32::try_from(fsst_compressed.len()).map_err(|_| CoreError::Corrupt {
reason: format!(
"fsst+brotli: fsst_compressed length {} exceeds u32",
fsst_compressed.len()
),
})?;
out.extend_from_slice(&fsst_len.to_le_bytes());
out.extend_from_slice(&fsst_compressed);
out.extend_from_slice(&brotli_compressed);
Ok(out)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn round_trips_csv_like_input() {
let input = b"id,name,city\n1,alice,paris\n2,bob,london\n3,carol,paris\n".repeat(200);
let c = FsstBrotliCodec;
let compressed = c.compress(&input).expect("compress");
let plain = brotli::compress(&input, DEFAULT_QUALITY).expect("plain brotli");
assert!(
compressed.len() <= plain.len() + 8,
"composite ({}) should not be much worse than plain Brotli ({})",
compressed.len(),
plain.len()
);
let recovered = c
.decompress(&compressed, input.len() as u32)
.expect("decompress");
assert_eq!(recovered, input);
}
#[test]
fn round_trips_small_input_uses_no_fsst_form() {
let input = b"hello world hello world";
let c = FsstBrotliCodec;
let compressed = c.compress(input).expect("compress");
let mut len_bytes = [0u8; 4];
len_bytes.copy_from_slice(&compressed[..4]);
assert_eq!(u32::from_le_bytes(len_bytes), 0);
let recovered = c
.decompress(&compressed, input.len() as u32)
.expect("decompress");
assert_eq!(recovered.as_slice(), input);
}
}