use super::adaptive_encode::{CompressionCodec, DeltaEncoder, DictionaryEncoder, RLEEncoder};
use super::codec_encode::CodecMetadata;
use crate::error::TauqError;
use serde_json::Value;
#[derive(Debug, Clone)]
pub struct CodecDecodingContext {
pub codec: CompressionCodec,
pub metadata: CodecMetadata,
pub delta_encoder: Option<DeltaEncoder>,
pub dict_encoder: Option<DictionaryEncoder>,
pub rle_encoder: Option<RLEEncoder>,
}
impl CodecDecodingContext {
pub fn from_metadata(codec: CompressionCodec, metadata: CodecMetadata) -> Self {
Self {
codec,
metadata,
delta_encoder: None,
dict_encoder: None,
rle_encoder: None,
}
}
pub fn initialize_decoders(&mut self) {
match self.codec {
CompressionCodec::Delta => {
if let CodecMetadata::Delta { initial_value } = self.metadata {
self.delta_encoder = Some(DeltaEncoder::new(initial_value));
}
}
CompressionCodec::Dictionary => {
self.dict_encoder = Some(DictionaryEncoder::new());
}
CompressionCodec::RunLength => {
self.rle_encoder = Some(RLEEncoder::new());
}
CompressionCodec::Raw => {
}
}
}
pub fn decode_value(&mut self, encoded_value: &Value) -> Result<Value, TauqError> {
match self.codec {
CompressionCodec::Delta => {
if let Some(num) = encoded_value.as_i64() {
if self.delta_encoder.is_some() {
Ok(Value::Number(num.into()))
} else {
Err(TauqError::Interpret(crate::error::InterpretError::new(
"Delta encoder not initialized",
)))
}
} else {
Ok(encoded_value.clone())
}
}
CompressionCodec::Dictionary => {
if let Some(ref encoder) = self.dict_encoder {
if let Some(idx) = encoded_value.as_u64() {
let dictionary = encoder.dictionary();
if (idx as usize) < dictionary.len() {
Ok(dictionary[idx as usize].clone())
} else {
Ok(encoded_value.clone())
}
} else {
Ok(encoded_value.clone())
}
} else {
Ok(encoded_value.clone())
}
}
CompressionCodec::RunLength => {
if self.rle_encoder.is_some() {
Ok(encoded_value.clone())
} else {
Ok(encoded_value.clone())
}
}
CompressionCodec::Raw => {
Ok(encoded_value.clone())
}
}
}
pub fn is_active(&self) -> bool {
!matches!(self.codec, CompressionCodec::Raw)
}
}
pub fn decode_codec_metadata(bytes: &[u8]) -> Result<(CompressionCodec, CodecMetadata), TauqError> {
if bytes.is_empty() {
return Ok((CompressionCodec::Raw, CodecMetadata::None));
}
let codec_type = bytes[0];
let codec = match codec_type {
0 => CompressionCodec::Raw,
1 => CompressionCodec::Delta,
2 => CompressionCodec::Dictionary,
3 => CompressionCodec::RunLength,
_ => {
return Err(TauqError::Interpret(crate::error::InterpretError::new(
format!("Unknown codec type: {}", codec_type),
)));
}
};
let metadata = match codec {
CompressionCodec::Delta => {
if bytes.len() > 1 {
let (value, _) = super::varint::decode_signed_varint(&bytes[1..])?;
CodecMetadata::Delta {
initial_value: value,
}
} else {
CodecMetadata::Delta { initial_value: 0 }
}
}
CompressionCodec::Dictionary => {
if bytes.len() > 1 {
let (size, _) = super::varint::decode_varint(&bytes[1..])?;
CodecMetadata::Dictionary {
dictionary_size: size as u32,
}
} else {
CodecMetadata::Dictionary { dictionary_size: 0 }
}
}
CompressionCodec::RunLength => CodecMetadata::RLE,
CompressionCodec::Raw => CodecMetadata::None,
};
Ok((codec, metadata))
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn test_codec_decoding_context_creation() {
let ctx = CodecDecodingContext::from_metadata(
CompressionCodec::Delta,
CodecMetadata::Delta { initial_value: 100 },
);
assert_eq!(ctx.codec, CompressionCodec::Delta);
assert!(matches!(ctx.metadata, CodecMetadata::Delta { .. }));
}
#[test]
fn test_delta_decoder_initialization() {
let mut ctx = CodecDecodingContext::from_metadata(
CompressionCodec::Delta,
CodecMetadata::Delta { initial_value: 50 },
);
ctx.initialize_decoders();
assert!(ctx.delta_encoder.is_some());
}
#[test]
fn test_dictionary_decoder_initialization() {
let mut ctx = CodecDecodingContext::from_metadata(
CompressionCodec::Dictionary,
CodecMetadata::Dictionary {
dictionary_size: 100,
},
);
ctx.initialize_decoders();
assert!(ctx.dict_encoder.is_some());
}
#[test]
fn test_rle_decoder_initialization() {
let mut ctx =
CodecDecodingContext::from_metadata(CompressionCodec::RunLength, CodecMetadata::RLE);
ctx.initialize_decoders();
assert!(ctx.rle_encoder.is_some());
}
#[test]
fn test_raw_codec_no_initialization() {
let mut ctx =
CodecDecodingContext::from_metadata(CompressionCodec::Raw, CodecMetadata::None);
ctx.initialize_decoders();
assert!(ctx.delta_encoder.is_none());
assert!(ctx.dict_encoder.is_none());
assert!(ctx.rle_encoder.is_none());
}
#[test]
fn test_codec_active_check() {
let ctx_raw =
CodecDecodingContext::from_metadata(CompressionCodec::Raw, CodecMetadata::None);
assert!(!ctx_raw.is_active());
let ctx_delta = CodecDecodingContext::from_metadata(
CompressionCodec::Delta,
CodecMetadata::Delta { initial_value: 0 },
);
assert!(ctx_delta.is_active());
}
#[test]
fn test_decode_raw_value() {
let mut ctx =
CodecDecodingContext::from_metadata(CompressionCodec::Raw, CodecMetadata::None);
ctx.initialize_decoders();
let value = json!("test");
let result = ctx.decode_value(&value).unwrap();
assert_eq!(result, json!("test"));
}
#[test]
fn test_decode_codec_metadata_raw() {
let (_codec, _metadata) = decode_codec_metadata(&[]).unwrap();
}
#[test]
fn test_decode_codec_metadata_delta() {
let mut bytes = vec![1]; crate::tbf::varint::encode_signed_varint(42i64, &mut bytes);
let (codec, metadata) = decode_codec_metadata(&bytes).unwrap();
assert_eq!(codec, CompressionCodec::Delta);
assert!(matches!(metadata, CodecMetadata::Delta { .. }));
}
#[test]
fn test_decode_codec_metadata_dictionary() {
let mut bytes = vec![2]; crate::tbf::varint::encode_varint(100u64, &mut bytes);
let (codec, metadata) = decode_codec_metadata(&bytes).unwrap();
assert_eq!(codec, CompressionCodec::Dictionary);
assert!(matches!(metadata, CodecMetadata::Dictionary { .. }));
}
#[test]
fn test_decode_codec_metadata_rle() {
let bytes = vec![3];
let (codec, metadata) = decode_codec_metadata(&bytes).unwrap();
assert_eq!(codec, CompressionCodec::RunLength);
assert!(matches!(metadata, CodecMetadata::RLE));
}
#[test]
fn test_decode_invalid_codec_type() {
let bytes = vec![99];
let result = decode_codec_metadata(&bytes);
assert!(result.is_err());
}
}