use std::io::Result;
use bytes::{Buf, BufMut};
use lzzzz::lz4::{ACC_LEVEL_DEFAULT, compress, decompress, max_compressed_size};
use crate::vpm::{VirtualPageEncoding, VirtualPageEncodingType,
page_manager::PAGE_HEADER_SIZE};
const MIN_SOURCE_SIZE: usize = 128;
const ENCODING_HEADER_LEN: usize = 8;
pub struct LZ4EncoderBuilder {
level: i32, threshold: usize, }
impl LZ4EncoderBuilder {
pub fn new() -> Self {
LZ4EncoderBuilder {
level: ACC_LEVEL_DEFAULT,
threshold: MIN_SOURCE_SIZE,
}
}
pub fn set_level(mut self, level: u8) -> Self {
self.level = level as i32;
self
}
pub fn set_threshold(mut self, threshold: usize) -> Self {
self.threshold = threshold;
self
}
pub fn build(self) -> LZ4Encoder {
LZ4Encoder {
level: self.level,
threshold: self.threshold,
}
}
}
#[derive(Debug, Clone)]
pub struct LZ4Encoder {
level: i32, threshold: usize, }
impl VirtualPageEncoding for LZ4Encoder {
type Raw = Vec<u8>;
type Encoded = Vec<u8>;
fn encoding_type(&self) -> VirtualPageEncodingType {
VirtualPageEncodingType::LZ4(self.level as u8)
}
fn encode(&self, raw: Self::Raw) -> Result<Self::Encoded> {
if raw.len() <= self.threshold {
let mut uncompressed = vec![0; ENCODING_HEADER_LEN];
uncompressed.extend_from_slice(raw.as_slice());
Ok(uncompressed)
} else {
let max_compressed_size = max_compressed_size(raw.len());
let capacity = if max_compressed_size == 0 {
raw.len() + ENCODING_HEADER_LEN
} else {
max_compressed_size + ENCODING_HEADER_LEN
};
let mut compressed = Vec::with_capacity(capacity);
compressed.put_u64_le(raw.len() as u64);
compressed.resize(capacity, 0);
let len = compress(raw.as_slice(),
&mut compressed[ENCODING_HEADER_LEN..capacity],
self.level)?;
compressed.truncate(len + ENCODING_HEADER_LEN);
Ok(compressed)
}
}
fn decode(&self, encoded: Self::Encoded, page_len: usize) -> Result<Self::Raw> {
let mut slice = &encoded[PAGE_HEADER_SIZE..PAGE_HEADER_SIZE + page_len];
match slice.get_u64_le() {
0 => {
Ok(slice.to_vec())
},
raw_len => {
let mut decompressed = vec![0; raw_len as usize];
let len = decompress(slice, decompressed.as_mut())?;
decompressed.truncate(len);
Ok(decompressed)
},
}
}
}
impl LZ4Encoder {
pub fn level(&self) -> u8 {
self.level as u8
}
pub fn threshold(&self) -> usize {
self.threshold
}
}