use std::mem;
use super::rle::RleEncoder;
use crate::data_type::AsBytes;
use crate::util::bit_util::num_required_bits;
pub enum LevelEncoder {
Rle(RleEncoder),
RleV2(RleEncoder),
}
impl LevelEncoder {
pub fn v1_streaming(max_level: i16) -> Self {
let bit_width = num_required_bits(max_level as u64);
let buffer = vec![0u8; 4];
LevelEncoder::Rle(RleEncoder::new_from_buf(bit_width, buffer))
}
pub fn v2_streaming(max_level: i16) -> Self {
let bit_width = num_required_bits(max_level as u64);
LevelEncoder::RleV2(RleEncoder::new_from_buf(bit_width, Vec::new()))
}
#[inline]
pub fn put_with_observer<F>(&mut self, buffer: &[i16], mut observer: F) -> usize
where
F: FnMut(i16, usize),
{
match *self {
LevelEncoder::Rle(ref mut encoder) | LevelEncoder::RleV2(ref mut encoder) => {
let mut remaining = buffer;
while let Some((&value, rest)) = remaining.split_first() {
encoder.put(value as u64);
if encoder.is_accumulating_rle(value as u64) {
let run_len = rest.iter().take_while(|&&v| v == value).count();
if run_len > 0 {
encoder.extend_run(run_len);
}
observer(value, 1 + run_len);
remaining = &rest[run_len..];
} else {
observer(value, 1);
remaining = rest;
}
}
buffer.len()
}
}
}
#[inline]
#[allow(unused)]
pub fn consume(self) -> Vec<u8> {
match self {
LevelEncoder::Rle(encoder) => {
let mut encoded_data = encoder.consume();
let encoded_len = encoded_data.len() - mem::size_of::<i32>();
let len = (encoded_len as i32).to_le();
let len_bytes = len.as_bytes();
encoded_data[0..len_bytes.len()].copy_from_slice(len_bytes);
encoded_data
}
LevelEncoder::RleV2(encoder) => encoder.consume(),
}
}
#[inline]
pub fn flush_to<F, R>(&mut self, f: F) -> R
where
F: FnOnce(&[u8]) -> R,
{
let result = match self {
LevelEncoder::Rle(encoder) => {
let data = encoder.flush_buffer_mut();
let encoded_len = (data.len() - mem::size_of::<i32>()) as i32;
data[..4].copy_from_slice(&encoded_len.to_le_bytes());
f(data)
}
LevelEncoder::RleV2(encoder) => f(encoder.flush_buffer()),
};
match self {
LevelEncoder::Rle(encoder) => {
encoder.clear();
encoder.skip(mem::size_of::<i32>());
}
LevelEncoder::RleV2(encoder) => encoder.clear(),
}
result
}
}