use crate::io::error::IoResult;
use flate2::{read::GzDecoder, write::GzEncoder, Compression};
use std::io::{Read, Write};
pub fn compress_data<R, W>(reader: &mut R, writer: &mut W) -> IoResult<()>
where
R: Read,
W: Write,
{
let mut encoder = GzEncoder::new(writer, Compression::default());
std::io::copy(reader, &mut encoder)?;
encoder.finish()?;
Ok(())
}
pub fn decompress_data<R, W>(reader: &mut R, writer: &mut W) -> IoResult<()>
where
R: Read,
W: Write,
{
let mut decoder = GzDecoder::new(reader);
std::io::copy(&mut decoder, writer)?;
Ok(())
}
#[allow(dead_code)]
pub fn compress_bytes(data: &[u8]) -> IoResult<Vec<u8>> {
let mut encoder = GzEncoder::new(Vec::new(), Compression::default());
encoder.write_all(data)?;
let compressed = encoder.finish()?;
Ok(compressed)
}
#[allow(dead_code)]
pub fn decompress_bytes(data: &[u8]) -> IoResult<Vec<u8>> {
let mut decoder = GzDecoder::new(data);
let mut decompressed = Vec::new();
decoder.read_to_end(&mut decompressed)?;
Ok(decompressed)
}
#[derive(Debug, Clone)]
#[allow(dead_code)]
pub struct CompressionConfig {
pub level: u32,
pub fast: bool,
}
impl CompressionConfig {
pub fn new() -> Self {
Self {
level: 6, fast: false,
}
}
pub fn fast() -> Self {
Self {
level: 1,
fast: true,
}
}
pub fn best() -> Self {
Self {
level: 9,
fast: false,
}
}
pub fn with_level(level: u32) -> Self {
Self {
level: level.min(9),
fast: false,
}
}
}
impl Default for CompressionConfig {
fn default() -> Self {
Self::new()
}
}
#[allow(dead_code)]
pub struct CompressedReader<R> {
inner: GzDecoder<R>,
}
impl<R: Read> CompressedReader<R> {
pub fn new(reader: R) -> Self {
Self {
inner: GzDecoder::new(reader),
}
}
pub fn get_ref(&self) -> &GzDecoder<R> {
&self.inner
}
pub fn get_mut(&mut self) -> &mut GzDecoder<R> {
&mut self.inner
}
pub fn into_inner(self) -> GzDecoder<R> {
self.inner
}
}
impl<R: Read> Read for CompressedReader<R> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
self.inner.read(buf)
}
}
#[allow(dead_code)]
pub struct CompressedWriter<W: Write> {
inner: GzEncoder<W>,
}
impl<W: Write> CompressedWriter<W> {
pub fn new(writer: W) -> Self {
Self {
inner: GzEncoder::new(writer, Compression::default()),
}
}
pub fn with_level(writer: W, level: u32) -> Self {
Self {
inner: GzEncoder::new(writer, Compression::new(level)),
}
}
pub fn with_config(writer: W, config: CompressionConfig) -> Self {
let compression = if config.fast {
Compression::fast()
} else {
Compression::new(config.level)
};
Self {
inner: GzEncoder::new(writer, compression),
}
}
pub fn finish(self) -> std::io::Result<W> {
self.inner.finish()
}
pub fn get_ref(&self) -> &W {
self.inner.get_ref()
}
pub fn get_mut(&mut self) -> &mut W {
self.inner.get_mut()
}
}
impl<W: Write> Write for CompressedWriter<W> {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.inner.write(buf)
}
fn flush(&mut self) -> std::io::Result<()> {
self.inner.flush()
}
}
#[allow(dead_code)]
pub mod analyze {
use super::*;
pub fn compression_ratio(original_size: usize, compressed_size: usize) -> f64 {
if original_size == 0 {
0.0
} else {
compressed_size as f64 / original_size as f64
}
}
pub fn space_savings(original_size: usize, compressed_size: usize) -> f64 {
if original_size == 0 {
0.0
} else {
(1.0 - compression_ratio(original_size, compressed_size)) * 100.0
}
}
pub fn test_compression(data: &[u8]) -> IoResult<CompressionStats> {
let compressed = compress_bytes(data)?;
Ok(CompressionStats {
original_size: data.len(),
compressed_size: compressed.len(),
ratio: compression_ratio(data.len(), compressed.len()),
savings_percent: space_savings(data.len(), compressed.len()),
})
}
#[derive(Debug, Clone)]
pub struct CompressionStats {
pub original_size: usize,
pub compressed_size: usize,
pub ratio: f64,
pub savings_percent: f64,
}
}