#![cfg(feature = "compression")]
#![cfg_attr(docsrs, doc(cfg(feature = "compression")))]
use std::io::{self, Read, Write};
use crate::prelude::Flags;
use super::error::*;
use lz4_flex as lz4;
use snap;
use brotli;
#[derive(Debug)]
#[cfg_attr(docsrs, doc(cfg(feature = "compression")))]
pub struct Compressor<T: Read> {
data: T,
}
impl<T: Read> Compressor<T> {
pub fn new(data: T) -> Compressor<T> {
Compressor { data }
}
pub fn compress(&mut self, algo: CompressionAlgorithm, output: &mut dyn Write) -> InternalResult {
match algo {
CompressionAlgorithm::LZ4 => {
let mut compressor = lz4::frame::FrameEncoder::new(output);
io::copy(&mut self.data, &mut compressor)?;
compressor.finish()?;
Ok(())
},
CompressionAlgorithm::Snappy => {
let mut compressor = snap::read::FrameEncoder::new(&mut self.data);
io::copy(&mut compressor, output)?;
Ok(())
},
CompressionAlgorithm::Brotli(quality) if quality < 12 && quality > 0 => {
let mut compressor = brotli::CompressorReader::new(&mut self.data, 4096, quality, 21u32);
io::copy(&mut compressor, output)?;
Ok(())
},
CompressionAlgorithm::Brotli(_) => Err(InternalError::OtherError(
"Maximum Brotli compression level is 11 and minimum is 1".into(),
)),
}
}
pub fn decompress(&mut self, algo: CompressionAlgorithm, output: &mut Vec<u8>) -> InternalResult<usize> {
match algo {
CompressionAlgorithm::LZ4 => {
let mut rdr = lz4::frame::FrameDecoder::new(&mut self.data);
rdr.read_to_end(output).map_err(InternalError::IOError)
},
CompressionAlgorithm::Snappy => {
let mut rdr = snap::read::FrameDecoder::new(&mut self.data);
rdr.read_to_end(output).map_err(InternalError::IOError)
},
CompressionAlgorithm::Brotli(_) => {
let mut rdr = brotli::Decompressor::new(&mut self.data, 4096);
rdr.read_to_end(output).map_err(InternalError::IOError)
},
}
}
}
#[cfg_attr(docsrs, doc(cfg(feature = "compression")))]
#[derive(Clone, Copy, Debug, Default)]
pub enum CompressionAlgorithm {
Snappy,
#[default]
LZ4,
Brotli(u32),
}
impl std::fmt::Display for CompressionAlgorithm {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
CompressionAlgorithm::Snappy => write!(f, "Snappy"),
CompressionAlgorithm::LZ4 => write!(f, "LZ4"),
CompressionAlgorithm::Brotli(_) => write!(f, "Brotli"),
}
}
}
impl From<CompressionAlgorithm> for u32 {
fn from(algo: CompressionAlgorithm) -> Self {
match algo {
CompressionAlgorithm::Snappy => Flags::SNAPPY_COMPRESSED,
CompressionAlgorithm::LZ4 => Flags::LZ4_COMPRESSED,
CompressionAlgorithm::Brotli(_) => Flags::BROTLI_COMPRESSED,
}
}
}