#![allow(missing_docs)]
pub mod adaptive;
pub mod brotli_compressor;
pub mod delta;
pub mod error;
pub mod metrics;
pub mod per_type_compressor;
pub mod smart_compressor;
pub mod zlib_compressor;
pub mod zstd_compressor;
use std::fmt::Debug;
pub use adaptive::{
calculate_entropy, AdaptiveCompressor, CompressionStrategy as AdaptiveStrategy, EntropyClass,
FileProfile, PatternClass, PerformanceStats, SizeClass,
};
pub use brotli_compressor::BrotliCompressor;
pub use error::{CompressionError, CompressionResult};
pub use metrics::{AggregatedStats, CompressionMetrics, MetricsAggregator};
pub use per_type_compressor::{CompressionProfile, PerObjectTypeCompressor, PerTypeStats};
pub use smart_compressor::{
CompressionStrategy, ObjectCategory, ObjectType, SmartCompressor, TypeAwareCompressor,
};
pub use zlib_compressor::ZlibCompressor;
pub use zstd_compressor::ZstdCompressor;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CompressionLevel {
Fast,
Default,
Best,
}
impl CompressionLevel {
pub fn to_zstd_level(self) -> i32 {
match self {
CompressionLevel::Fast => 1,
CompressionLevel::Default => 3,
CompressionLevel::Best => 22,
}
}
pub fn to_brotli_level(self) -> u32 {
match self {
CompressionLevel::Fast => 4,
CompressionLevel::Default => 9,
CompressionLevel::Best => 11,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[repr(u8)]
pub enum CompressionAlgorithm {
None = 0,
Zlib = 1,
Zstd = 2,
Brotli = 3,
}
impl CompressionAlgorithm {
pub fn magic_bytes(self) -> &'static [u8] {
match self {
CompressionAlgorithm::None => b"",
CompressionAlgorithm::Zlib => b"\x78", CompressionAlgorithm::Zstd => b"\x28\xb5\x2f\xfd", CompressionAlgorithm::Brotli => b"BRT\x01", }
}
pub fn detect(data: &[u8]) -> Self {
if data.is_empty() {
return CompressionAlgorithm::None;
}
if data.len() >= 4 {
if data.starts_with(b"\x28\xb5\x2f\xfd") {
return CompressionAlgorithm::Zstd;
}
if data.starts_with(b"BRT\x01") {
return CompressionAlgorithm::Brotli;
}
}
if data.len() >= 2 && data[0] == 0x78 {
let cmf = data[0] as u16;
let flg = data[1] as u16;
let header_check = cmf * 256 + flg;
if header_check.is_multiple_of(31) {
return CompressionAlgorithm::Zlib;
}
}
CompressionAlgorithm::None
}
}
pub trait Compressor: Send + Sync + Debug {
fn compress(&self, data: &[u8]) -> CompressionResult<Vec<u8>>;
fn decompress(&self, data: &[u8]) -> CompressionResult<Vec<u8>>;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn compression_level_conversions() {
assert_eq!(CompressionLevel::Fast.to_zstd_level(), 1);
assert_eq!(CompressionLevel::Default.to_zstd_level(), 3);
assert_eq!(CompressionLevel::Best.to_zstd_level(), 22);
assert_eq!(CompressionLevel::Fast.to_brotli_level(), 4);
assert_eq!(CompressionLevel::Default.to_brotli_level(), 9);
assert_eq!(CompressionLevel::Best.to_brotli_level(), 11);
}
#[test]
fn algorithm_detection() {
let zlib_data = b"\x78\x9c\x00\x00\x00\x00";
assert_eq!(
CompressionAlgorithm::detect(zlib_data),
CompressionAlgorithm::Zlib
);
let zstd_data = b"\x28\xb5\x2f\xfd\x00\x00\x00\x00";
assert_eq!(
CompressionAlgorithm::detect(zstd_data),
CompressionAlgorithm::Zstd
);
let brotli_data = b"BRT\x01some_data";
assert_eq!(
CompressionAlgorithm::detect(brotli_data),
CompressionAlgorithm::Brotli
);
let raw_data = b"Hello, World!";
assert_eq!(
CompressionAlgorithm::detect(raw_data),
CompressionAlgorithm::None
);
let empty_data = b"";
assert_eq!(
CompressionAlgorithm::detect(empty_data),
CompressionAlgorithm::None
);
}
#[test]
fn compression_level_debug() {
assert_eq!(format!("{:?}", CompressionLevel::Fast), "Fast");
assert_eq!(format!("{:?}", CompressionLevel::Default), "Default");
assert_eq!(format!("{:?}", CompressionLevel::Best), "Best");
}
}