use alloc::vec::Vec;
use lz4_flex::{compress_prepend_size, decompress_size_prepended};
#[cfg(feature = "std")]
use std::io::{Read, Write};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CompressionType {
None = 0,
Lz4 = 1,
#[cfg(feature = "std")]
Zstd = 2,
#[cfg(feature = "std")]
Lzma = 3,
}
pub struct Lz4Compressor;
#[cfg(feature = "std")]
pub struct ZstdCompressor;
#[cfg(feature = "std")]
pub struct LzmaCompressor;
pub struct Compress;
impl Compress {
pub fn compress_with_type(data: &[u8], comp_type: CompressionType) -> Option<Vec<u8>> {
match comp_type {
CompressionType::None => Some(data.to_vec()),
CompressionType::Lz4 => Lz4Compressor::compress(data).ok(),
#[cfg(feature = "std")]
CompressionType::Zstd => ZstdCompressor::compress(data).ok(),
#[cfg(feature = "std")]
CompressionType::Lzma => LzmaCompressor::compress(data).ok(),
}
}
pub fn decompress_with_type(data: &[u8], comp_type: CompressionType) -> Option<Vec<u8>> {
match comp_type {
CompressionType::None => Some(data.to_vec()),
CompressionType::Lz4 => Lz4Compressor::decompress(data, 0).ok(),
#[cfg(feature = "std")]
CompressionType::Zstd => ZstdCompressor::decompress(data).ok(),
#[cfg(feature = "std")]
CompressionType::Lzma => LzmaCompressor::decompress(data).ok(),
}
}
pub fn compress(data: &[u8]) -> Option<Vec<u8>> {
Lz4Compressor::compress(data).ok()
}
pub fn decompress(data: &[u8]) -> Option<Vec<u8>> {
Lz4Compressor::decompress(data, 0).ok()
}
}
impl Lz4Compressor {
pub fn compress(data: &[u8]) -> Result<Vec<u8>, &'static str> {
if data.len() < 64 {
return Ok(data.to_vec());
}
let compressed = compress_prepend_size(data);
if compressed.len() >= data.len() {
return Ok(data.to_vec());
}
Ok(compressed)
}
pub fn decompress(compressed: &[u8], _original_size: usize) -> Result<Vec<u8>, &'static str> {
decompress_size_prepended(compressed).map_err(|_| "LZ4 Decompression Failed")
}
}
#[cfg(feature = "std")]
impl ZstdCompressor {
pub fn compress(data: &[u8]) -> Result<Vec<u8>, &'static str> {
if data.len() < 128 {
return Ok(data.to_vec());
}
let compressed = zstd::encode_all(data, 3).map_err(|_| "ZSTD compression failed")?;
if compressed.len() >= data.len() {
return Ok(data.to_vec());
}
Ok(compressed)
}
pub fn decompress(compressed: &[u8]) -> Result<Vec<u8>, &'static str> {
zstd::decode_all(compressed).map_err(|_| "ZSTD decompression failed")
}
}
#[cfg(feature = "std")]
impl LzmaCompressor {
pub fn compress(data: &[u8]) -> Result<Vec<u8>, &'static str> {
if data.len() < 256 {
return Ok(data.to_vec());
}
let mut compressed = Vec::new();
let mut encoder = xz2::write::XzEncoder::new(&mut compressed, 6);
encoder
.write_all(data)
.map_err(|_| "LZMA compression write failed")?;
encoder
.finish()
.map_err(|_| "LZMA compression finish failed")?;
if compressed.len() >= data.len() {
return Ok(data.to_vec());
}
Ok(compressed)
}
pub fn decompress(compressed: &[u8]) -> Result<Vec<u8>, &'static str> {
let mut decompressed = Vec::new();
let mut decoder = xz2::read::XzDecoder::new(compressed);
decoder
.read_to_end(&mut decompressed)
.map_err(|_| "LZMA decompression failed")?;
Ok(decompressed)
}
}