use flate2::{
write::{GzEncoder, GzDecoder, DeflateEncoder, DeflateDecoder, ZlibEncoder, ZlibDecoder},
Compression,
};
use flate2::read::{DeflateEncoder as RawDeflateEncoder, DeflateDecoder as RawDeflateDecoder};
use std::io::{Read, Write};
use serde::{Deserialize, Serialize};
use bincode;
#[derive(Debug)]
pub enum BunkoError {
CompressionError(String),
DecompressionError(String),
Utf8Error(String),
SerializationError(String),
DeserializationError(String),
}
impl std::fmt::Display for BunkoError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}
impl std::error::Error for BunkoError {}
impl From<std::string::FromUtf8Error> for BunkoError {
fn from(err: std::string::FromUtf8Error) -> Self {
BunkoError::Utf8Error(err.to_string())
}
}
pub enum CompressionFormat {
Gzip,
Deflate,
Zlib,
}
pub enum CompressionLevel {
Fastest,
Default,
Best,
}
impl CompressionLevel {
fn to_flate2_compression(&self) -> Compression {
match self {
CompressionLevel::Fastest => Compression::fast(),
CompressionLevel::Default => Compression::default(),
CompressionLevel::Best => Compression::best(),
}
}
}
pub fn compress(
input: &[u8],
format: CompressionFormat,
level: CompressionLevel,
) -> Result<Vec<u8>, String> {
let compression = level.to_flate2_compression();
match format {
CompressionFormat::Gzip => {
let mut encoder = GzEncoder::new(Vec::new(), compression);
encoder
.write_all(input)
.map_err(|e| format!("Compression error: {}", e))?;
encoder
.finish()
.map_err(|e| format!("Failed to finish compression: {}", e))
}
CompressionFormat::Deflate => {
let mut encoder = DeflateEncoder::new(Vec::new(), compression);
encoder
.write_all(input)
.map_err(|e| format!("Compression error: {}", e))?;
encoder
.finish()
.map_err(|e| format!("Failed to finish compression: {}", e))
}
CompressionFormat::Zlib => {
let mut encoder = ZlibEncoder::new(Vec::new(), compression);
encoder
.write_all(input)
.map_err(|e| format!("Compression error: {}", e))?;
encoder
.finish()
.map_err(|e| format!("Failed to finish compression: {}", e))
}
}
}
pub fn decompress(input: &[u8], format: CompressionFormat) -> Result<Vec<u8>, String> {
match format {
CompressionFormat::Gzip => {
let mut decoder = GzDecoder::new(Vec::new());
decoder
.write_all(input)
.map_err(|e| format!("Decompression error: {}", e))?;
decoder
.finish()
.map_err(|e| format!("Failed to finish decompression: {}", e))
}
CompressionFormat::Deflate => {
let mut decoder = DeflateDecoder::new(Vec::new());
decoder
.write_all(input)
.map_err(|e| format!("Decompression error: {}", e))?;
decoder
.finish()
.map_err(|e| format!("Failed to finish decompression: {}", e))
}
CompressionFormat::Zlib => {
let mut encoder = ZlibDecoder::new(Vec::new());
encoder
.write_all(input)
.map_err(|e| format!("Compression error: {}", e))?;
encoder
.finish()
.map_err(|e| format!("Failed to finish compression: {}", e))
}
}
}
pub fn compress_raw(input: &[u8], level: CompressionLevel) -> Result<Vec<u8>, BunkoError> {
let compression = level.to_flate2_compression();
let mut encoder = RawDeflateEncoder::new(input, compression);
let mut compressed = Vec::new();
encoder
.read_to_end(&mut compressed)
.map_err(|e| BunkoError::CompressionError(e.to_string()))?;
Ok(compressed)
}
pub fn decompress_raw(input: &[u8]) -> Result<Vec<u8>, BunkoError> {
let mut decoder = RawDeflateDecoder::new(input);
let mut decompressed = Vec::new();
decoder
.read_to_end(&mut decompressed)
.map_err(|e| BunkoError::DecompressionError(e.to_string()))?;
Ok(decompressed)
}
pub fn compress_struct<T: Serialize>(
data: &T,
format: CompressionFormat,
level: CompressionLevel,
) -> Result<Vec<u8>, BunkoError> {
let serialized = bincode::serialize(data).map_err(|e| BunkoError::SerializationError(e.to_string()))?;
compress(&serialized, format, level).map_err(BunkoError::CompressionError)
}
pub fn decompress_struct<T: for<'de> Deserialize<'de>>(
compressed_data: &[u8],
format: CompressionFormat,
) -> Result<T, BunkoError> {
let decompressed = decompress(compressed_data, format).map_err(BunkoError::DecompressionError)?;
bincode::deserialize(&decompressed).map_err(|e| BunkoError::DeserializationError(e.to_string()))
}
pub fn compress_stream(
chunks: &[&[u8]],
format: CompressionFormat,
level: CompressionLevel,
) -> Result<Vec<u8>, String> {
let compression = level.to_flate2_compression();
match format {
CompressionFormat::Gzip => {
let mut encoder = GzEncoder::new(Vec::new(), compression);
for chunk in chunks {
encoder
.write_all(chunk)
.map_err(|e| format!("Stream compression error: {}", e))?;
}
encoder
.finish()
.map_err(|e| format!("Failed to finish streaming compression: {}", e))
}
CompressionFormat::Deflate => {
let mut encoder = DeflateEncoder::new(Vec::new(), compression);
for chunk in chunks {
encoder
.write_all(chunk)
.map_err(|e| format!("Stream compression error: {}", e))?;
}
encoder
.finish()
.map_err(|e| format!("Failed to finish streaming compression: {}", e))
}
CompressionFormat::Zlib => {
let mut encoder = ZlibEncoder::new(Vec::new(), compression);
for chunk in chunks {
encoder
.write_all(chunk)
.map_err(|e| format!("Stream compression error: {}", e))?;
}
encoder
.finish()
.map_err(|e| format!("Failed to finish streaming compression: {}", e))
}
}
}
pub fn decompress_stream(
chunks: &[&[u8]],
format: CompressionFormat,
) -> Result<Vec<u8>, String> {
match format {
CompressionFormat::Gzip => {
let mut decoder = GzDecoder::new(Vec::new());
for chunk in chunks {
decoder
.write_all(chunk)
.map_err(|e| format!("Stream decompression error: {}", e))?;
}
decoder
.finish()
.map_err(|e| format!("Failed to finish streaming decompression: {}", e))
}
CompressionFormat::Deflate => {
let mut decoder = DeflateDecoder::new(Vec::new());
for chunk in chunks {
decoder
.write_all(chunk)
.map_err(|e| format!("Stream decompression error: {}", e))?;
}
decoder
.finish()
.map_err(|e| format!("Failed to finish streaming decompression: {}", e))
}
CompressionFormat::Zlib => {
let mut decoder = ZlibDecoder::new(Vec::new());
for chunk in chunks {
decoder
.write_all(chunk)
.map_err(|e| format!("Stream decompression error: {}", e))?;
}
decoder
.finish()
.map_err(|e| format!("Failed to finish streaming decompression: {}", e))
}
}
}
pub fn compress_with_buffer(
input: &[u8],
format: CompressionFormat,
level: CompressionLevel,
buffer_size: usize,
) -> Result<Vec<u8>, BunkoError> {
let compression = level.to_flate2_compression();
match format {
CompressionFormat::Gzip => {
let mut encoder = GzEncoder::new(Vec::new(), compression);
for chunk in input.chunks(buffer_size) {
encoder
.write_all(chunk)
.map_err(|e| BunkoError::CompressionError(e.to_string()))?;
}
encoder
.finish()
.map_err(|e| BunkoError::CompressionError(e.to_string()))
}
CompressionFormat::Deflate => {
let mut encoder = DeflateEncoder::new(Vec::new(), compression);
for chunk in input.chunks(buffer_size) {
encoder
.write_all(chunk)
.map_err(|e| BunkoError::CompressionError(e.to_string()))?;
}
encoder
.finish()
.map_err(|e| BunkoError::CompressionError(e.to_string()))
}
CompressionFormat::Zlib => {
let mut encoder = ZlibEncoder::new(Vec::new(), compression);
for chunk in input.chunks(buffer_size) {
encoder
.write_all(chunk)
.map_err(|e| BunkoError::CompressionError(e.to_string()))?;
}
encoder
.finish()
.map_err(|e| BunkoError::CompressionError(e.to_string()))
}
}
}
pub fn compress_string(input: &str, level: CompressionLevel) -> Result<Vec<u8>, String> {
compress(input.as_bytes(), CompressionFormat::Gzip, level)
}
pub fn decompress_to_string(compressed_data: &[u8]) -> Result<String, String> {
let decompressed_data = decompress(compressed_data, CompressionFormat::Gzip)?;
String::from_utf8(decompressed_data).map_err(|e| format!("UTF-8 error: {}", e))
}
pub fn calculate_compression_ratio(original_size: usize, compressed_size: usize) -> f64 {
if original_size == 0 {
0.0
} else {
1.0 - (compressed_size as f64 / original_size as f64)
}
}