use crate::base_compressor::{BaseCompressor, State};
use crate::chunk_spec::ChunkSpec;
use crate::constants::MAGIC_TERMINATION_BYTE;
use crate::data_types::NumberLike;
use crate::errors::QCompressResult;
use crate::{bits, ChunkMetadata, CompressorConfig, Flags};
#[derive(Clone, Debug)]
pub struct Compressor<T: NumberLike>(BaseCompressor<T>);
impl<T: NumberLike> Default for Compressor<T> {
fn default() -> Self {
Self::from_config(CompressorConfig::default())
}
}
const DEFAULT_CHUNK_SIZE: usize = 1_000_000;
impl<T: NumberLike> Compressor<T> {
pub fn from_config(config: CompressorConfig) -> Self {
Self(BaseCompressor::<T>::from_config(
config, false,
))
}
pub fn flags(&self) -> &Flags {
&self.0.flags
}
pub fn header(&mut self) -> QCompressResult<()> {
self.0.header()
}
pub fn chunk(&mut self, nums: &[T]) -> QCompressResult<ChunkMetadata<T>> {
let pre_meta_bit_idx = self.0.writer.bit_size();
let mut meta = self
.0
.chunk_metadata_internal(nums, &ChunkSpec::default())?;
let post_meta_byte_idx = self.0.writer.byte_size();
self.0.data_page_internal()?;
meta.compressed_body_size = self.0.writer.byte_size() - post_meta_byte_idx;
meta.update_write_compressed_body_size(&mut self.0.writer, pre_meta_bit_idx);
Ok(meta)
}
pub fn footer(&mut self) -> QCompressResult<()> {
if !matches!(self.0.state, State::StartOfChunk) {
return Err(self.0.state.wrong_step_err("footer"));
}
self.0.writer.write_aligned_byte(MAGIC_TERMINATION_BYTE)?;
self.0.state = State::Terminated;
Ok(())
}
pub fn simple_compress(&mut self, nums: &[T]) -> Vec<u8> {
self.header().unwrap();
if !nums.is_empty() {
let n_chunks = bits::ceil_div(nums.len(), DEFAULT_CHUNK_SIZE);
let n_per_chunk = bits::ceil_div(nums.len(), n_chunks);
nums.chunks(n_per_chunk).for_each(|chunk| {
self.chunk(chunk).unwrap();
});
}
self.footer().unwrap();
self.drain_bytes()
}
pub fn drain_bytes(&mut self) -> Vec<u8> {
self.0.writer.drain_bytes()
}
pub fn byte_size(&mut self) -> usize {
self.0.writer.byte_size()
}
}