use crate::block::stream::Lz4Stream;
use crate::hc::api::{init_stream_hc, load_dict_hc, set_compression_level, Lz4StreamHc};
use crate::hc::types::LZ4HC_CLEVEL_DEFAULT;
const MAX_DICT_SIZE: usize = 64 * 1024;
pub struct Lz4FCDict {
pub(crate) dict_content: Vec<u8>,
pub(crate) fast_ctx: Box<Lz4Stream>,
pub(crate) hc_ctx: Box<Lz4StreamHc>,
}
unsafe impl Send for Lz4FCDict {}
unsafe impl Sync for Lz4FCDict {}
impl Lz4FCDict {
pub fn create(dict: &[u8]) -> Option<Box<Self>> {
let trimmed = if dict.len() > MAX_DICT_SIZE {
&dict[dict.len() - MAX_DICT_SIZE..]
} else {
dict
};
let dict_content: Vec<u8> = trimmed.to_vec();
let mut fast_ctx = Lz4Stream::new();
fast_ctx.load_dict_slow(trimmed);
let mut hc_ctx = Lz4StreamHc::create()?; init_stream_hc(&mut hc_ctx);
set_compression_level(&mut hc_ctx, LZ4HC_CLEVEL_DEFAULT);
unsafe {
load_dict_hc(
&mut hc_ctx,
dict_content.as_ptr(),
dict_content.len() as i32,
);
}
Some(Box::new(Lz4FCDict {
dict_content,
fast_ctx,
hc_ctx,
}))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn create_with_nonempty_dict() {
let dict: Vec<u8> = (0u8..=255).cycle().take(1024).collect();
let cdict = Lz4FCDict::create(&dict);
assert!(cdict.is_some(), "create should succeed with 1 KB dict");
let cdict = cdict.unwrap();
assert_eq!(cdict.dict_content.len(), dict.len().min(MAX_DICT_SIZE));
}
#[test]
fn create_with_empty_dict() {
let cdict = Lz4FCDict::create(&[]);
assert!(cdict.is_some());
let cdict = cdict.unwrap();
assert_eq!(cdict.dict_content.len(), 0);
}
#[test]
fn create_trims_large_dict() {
let dict: Vec<u8> = (0u8..=255).cycle().take(128 * 1024).collect();
let cdict = Lz4FCDict::create(&dict).expect("allocation failed");
assert_eq!(cdict.dict_content.len(), MAX_DICT_SIZE);
assert_eq!(
cdict.dict_content.as_slice(),
&dict[dict.len() - MAX_DICT_SIZE..]
);
}
#[test]
fn hc_stream_populated_after_create() {
let dict: Vec<u8> = b"The quick brown fox jumps over the lazy dog"
.iter()
.cycle()
.take(4096)
.copied()
.collect();
let cdict = Lz4FCDict::create(&dict).expect("allocation failed");
assert!(!cdict.dict_content.is_empty());
assert_eq!(
cdict.hc_ctx.ctx.compression_level as i32,
LZ4HC_CLEVEL_DEFAULT
);
}
}