use super::{CompressResult, CompressionError, Compressor};
use crate::bitmask::{packing, roaring};
pub struct RoaringCompressor;
impl Compressor for RoaringCompressor {
fn compress(&self, data: &[u8]) -> Result<CompressResult, CompressionError> {
let n_elements = data.len() * 8;
let bits = packing::unpack(data, n_elements)
.map_err(|e| CompressionError::Unknown(format!("Roaring compress unpack: {e}")))?;
let blob = roaring::encode(&bits)
.map_err(|e| CompressionError::Unknown(format!("Roaring encode: {e}")))?;
let mut out = Vec::with_capacity(4 + blob.len());
out.extend_from_slice(&(n_elements as u32).to_be_bytes());
out.extend_from_slice(&blob);
Ok(CompressResult {
data: out,
block_offsets: None,
})
}
fn decompress(&self, data: &[u8], expected_size: usize) -> Result<Vec<u8>, CompressionError> {
let Some((prefix, blob)) = data.split_first_chunk::<4>() else {
return Err(CompressionError::Unknown(
"Roaring blob too short: missing 4-byte n_elements prefix".to_string(),
));
};
let n_elements = u32::from_be_bytes(*prefix) as usize;
let bits = roaring::decode(blob, n_elements)
.map_err(|e| CompressionError::Unknown(format!("Roaring decode: {e}")))?;
let packed = packing::pack(&bits)
.map_err(|e| CompressionError::Unknown(format!("Roaring repack: {e}")))?;
if packed.len() != expected_size {
return Err(CompressionError::Unknown(format!(
"Roaring decompressed size {} != expected {}",
packed.len(),
expected_size
)));
}
Ok(packed)
}
fn decompress_range(
&self,
_data: &[u8],
_block_offsets: &[u64],
_byte_pos: usize,
_byte_size: usize,
) -> Result<Vec<u8>, CompressionError> {
Err(CompressionError::RangeNotSupported)
}
}