use crate::common::error::Result;
use super::traits::Compressor;
use super::algorithms::{CompressionAlgorithm, NoCompressor, GzipCompressor};
use std::sync::Arc;
use std::collections::HashMap;
use std::sync::RwLock;
lazy_static::lazy_static! {
static ref COMPRESSION_REGISTRY: CompressionRegistry = {
let registry = CompressionRegistry::new();
registry.register_defaults();
registry
};
}
pub struct CompressionRegistry {
compressors: Arc<RwLock<HashMap<String, Arc<dyn Compressor>>>>,
}
impl CompressionRegistry {
pub fn new() -> Self {
Self {
compressors: Arc::new(RwLock::new(HashMap::new())),
}
}
pub fn register_defaults(&self) {
self.register("none", Arc::new(NoCompressor));
self.register("gzip", Arc::new(GzipCompressor));
}
pub fn register(&self, name: &str, compressor: Arc<dyn Compressor>) {
if let Ok(mut compressors) = self.compressors.write() {
compressors.insert(name.to_string(), compressor);
}
}
pub fn find(&self, name: &str) -> Option<Arc<dyn Compressor>> {
self.compressors
.read()
.ok()
.and_then(|compressors| compressors.get(name).map(|c| Arc::clone(c)))
}
pub fn find_by_algorithm(&self, algorithm: CompressionAlgorithm) -> Option<Arc<dyn Compressor>> {
self.find(algorithm.as_str())
}
pub fn auto_detect(&self, data: &[u8]) -> Option<Arc<dyn Compressor>> {
if let Ok(compressors) = self.compressors.read() {
for compressor in compressors.values() {
if compressor.can_detect(data) {
return Some(Arc::clone(compressor));
}
}
}
None
}
pub fn global() -> &'static CompressionRegistry {
&COMPRESSION_REGISTRY
}
}
pub struct CompressionUtil;
impl CompressionUtil {
pub fn get_compressor(algorithm: CompressionAlgorithm) -> Arc<dyn Compressor> {
CompressionRegistry::global()
.find_by_algorithm(algorithm)
.unwrap_or_else(|| Arc::new(NoCompressor))
}
pub fn get_compressor_by_name(name: &str) -> Option<Arc<dyn Compressor>> {
CompressionRegistry::global().find(name)
}
pub fn compress(data: &[u8], algorithm: CompressionAlgorithm) -> Result<Vec<u8>> {
let compressor = Self::get_compressor(algorithm);
compressor.compress(data)
}
pub fn decompress(data: &[u8], algorithm: CompressionAlgorithm) -> Result<Vec<u8>> {
let compressor = Self::get_compressor(algorithm);
compressor.decompress(data)
}
pub fn auto_decompress(data: &[u8]) -> Result<(Vec<u8>, CompressionAlgorithm)> {
if let Some(compressor) = CompressionRegistry::global().auto_detect(data) {
let decompressed = compressor.decompress(data)?;
return Ok((decompressed, compressor.algorithm()));
}
Ok((data.to_vec(), CompressionAlgorithm::None))
}
pub fn register_custom(compressor: Arc<dyn Compressor>) {
CompressionRegistry::global().register(compressor.name(), compressor);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_compression_registry() {
let registry = CompressionRegistry::new();
registry.register_defaults();
assert!(registry.find("gzip").is_some());
assert!(registry.find("none").is_some());
assert!(registry.find("unknown").is_none());
}
#[test]
fn test_auto_detect() {
let data = b"\x1f\x8b\x08test"; let registry = CompressionRegistry::new();
registry.register_defaults();
let compressor = registry.auto_detect(data);
assert!(compressor.is_some());
assert_eq!(compressor.unwrap().algorithm(), CompressionAlgorithm::Gzip);
}
}