use lzma::{LzmaReader, LzmaWriter};
use num_enum::TryFromPrimitive;
use snap::read::FrameDecoder;
use snap::write::FrameEncoder;
use std::io::{Read, Write};
use crate::{BottleError, BottleResult};
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive)]
#[repr(u8)]
pub enum CompressionAlgorithm {
SNAPPY = 0,
LZMA2 = 1,
}
pub enum Compressor<W: Write> {
Snappy(FrameEncoder<W>),
Lzma2(LzmaWriter<W>),
}
impl<W: Write> Compressor<W> {
pub fn new(write: W, algorithm: CompressionAlgorithm) -> BottleResult<Compressor<W>> {
match algorithm {
CompressionAlgorithm::SNAPPY => Ok(Compressor::Snappy(FrameEncoder::new(write))),
CompressionAlgorithm::LZMA2 => {
let encoder = LzmaWriter::new_compressor(write, 9).map_err(BottleError::Lzma2Error)?;
Ok(Compressor::Lzma2(encoder))
},
}
}
pub fn close(self) -> BottleResult<W> {
match self {
Compressor::Snappy(encoder) => encoder.into_inner().map_err(|_| BottleError::CompressionError),
Compressor::Lzma2(encoder) => encoder.finish().map_err(BottleError::Lzma2Error),
}
}
}
impl<W: Write> Write for Compressor<W> {
fn write(&mut self, data: &[u8]) -> std::io::Result<usize> {
match self {
Compressor::Snappy(encoder) => encoder.write(data),
Compressor::Lzma2(encoder) => encoder.write(data),
}
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
pub enum Decompressor<R: Read> {
Snappy(FrameDecoder<R>),
Lzma2(LzmaReader<R>),
}
impl<R: Read> Decompressor<R> {
pub fn new(read: R, algorithm: CompressionAlgorithm) -> BottleResult<Decompressor<R>> {
match algorithm {
CompressionAlgorithm::SNAPPY => Ok(Decompressor::Snappy(FrameDecoder::new(read))),
CompressionAlgorithm::LZMA2 => {
let decoder = LzmaReader::new_decompressor(read).map_err(BottleError::Lzma2Error)?;
Ok(Decompressor::Lzma2(decoder))
},
}
}
}
impl<R: Read> Read for Decompressor<R> {
fn read(&mut self, buffer: &mut [u8]) -> std::io::Result<usize> {
match self {
Decompressor::Snappy(decoder) => decoder.read(buffer),
Decompressor::Lzma2(decoder) => decoder.read(buffer),
}
}
}