use anyhow::Result;
use ragc_common::types::{Contig, PackedBlock};
use std::cell::RefCell;
thread_local! {
static ZSTD_CCTX: RefCell<zstd_safe::CCtx<'static>> = RefCell::new(zstd_safe::CCtx::create());
}
pub fn compress_segment_pooled(data: &Contig, level: i32) -> Result<PackedBlock> {
ZSTD_CCTX.with(|cctx| {
let mut cctx = cctx.borrow_mut();
let max_compressed_size = zstd_safe::compress_bound(data.len());
let mut output = vec![0u8; max_compressed_size];
match cctx.compress(&mut output, data, level) {
Ok(compressed_size) => {
output.truncate(compressed_size);
Ok(output)
}
Err(code) => {
let msg = zstd_safe::get_error_name(code);
Err(anyhow::anyhow!("ZSTD compression failed: {}", msg))
}
}
})
}
pub fn decompress_segment_pooled(compressed: &PackedBlock) -> Result<Contig> {
zstd::decode_all(compressed.as_slice())
.map_err(|e| anyhow::anyhow!("Failed to decompress segment with ZSTD: {e}"))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_pooled_compress_decompress_roundtrip() {
let original = vec![0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3];
let compressed = compress_segment_pooled(&original, 11).unwrap();
let decompressed = decompress_segment_pooled(&compressed).unwrap();
assert_eq!(original, decompressed);
}
#[test]
fn test_pooled_multiple_compressions() {
for _ in 0..10 {
let original = vec![0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3];
let compressed = compress_segment_pooled(&original, 11).unwrap();
let decompressed = decompress_segment_pooled(&compressed).unwrap();
assert_eq!(original, decompressed);
}
}
#[test]
fn test_pooled_different_levels() {
let original = vec![0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3];
for level in [1, 3, 9, 17, 19].iter() {
let compressed = compress_segment_pooled(&original, *level).unwrap();
let decompressed = decompress_segment_pooled(&compressed).unwrap();
assert_eq!(original, decompressed);
}
}
#[test]
fn test_pooled_large_data() {
let mut original = Vec::new();
for i in 0..10000 {
original.push((i % 4) as u8);
}
let compressed = compress_segment_pooled(&original, 17).unwrap();
let decompressed = decompress_segment_pooled(&compressed).unwrap();
assert_eq!(original, decompressed);
assert!(compressed.len() < original.len());
}
}