#![cfg(not(target_arch = "wasm32"))]
use lz4::{Decoder as Lz4Decoder, EncoderBuilder as Lz4EncoderBuilder};
use std::io::{self, Read, Write};
use std::io::{BufRead, BufReader, BufWriter};
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub enum CompressionMode {
#[default]
None,
Lz4,
}
pub(crate) struct CompressedWriter {
inner: Box<dyn Write>,
}
impl CompressedWriter {
pub(crate) fn new<W: Write + 'static>(
writer: W,
compression_mode: CompressionMode,
) -> io::Result<Self> {
let inner: Box<dyn Write> = match compression_mode {
CompressionMode::None => {
Box::new(BufWriter::new(writer))
}
CompressionMode::Lz4 => {
let encoder = Lz4EncoderBuilder::new().level(7).build(writer)?;
Box::new(encoder)
}
};
Ok(Self {
inner,
})
}
pub(crate) fn finish(self) -> io::Result<()> {
Ok(())
}
}
impl Write for CompressedWriter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.inner.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.inner.flush()
}
}
pub(crate) struct CompressedReader {
inner: Box<dyn Read>,
}
impl CompressedReader {
pub(crate) fn new<R: Read + 'static>(reader: R) -> io::Result<Self> {
let mut buf_reader = BufReader::new(reader);
let compression = {
buf_reader.fill_buf()?;
let buffer = buf_reader.buffer();
if buffer.len() >= 4 {
if buffer[0..4] == [0x04, 0x22, 0x4D, 0x18] {
CompressionMode::Lz4
} else {
CompressionMode::None
}
} else {
CompressionMode::None
}
};
tracing::debug!("Detected snapshot compression: {compression:?}");
let inner: Box<dyn Read> = match compression {
CompressionMode::None => {
Box::new(buf_reader)
}
CompressionMode::Lz4 => {
let decoder = Lz4Decoder::new(buf_reader)?;
Box::new(decoder)
}
};
Ok(Self {
inner,
})
}
}
impl Read for CompressedReader {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.inner.read(buf)
}
}