use crate::FastPForResult;
use crate::codec::{AnyLenCodec, BlockCodec, slice_to_blocks};
use crate::helpers::AsUsize;
pub struct CompositeCodec<Blocks: BlockCodec, Tail: AnyLenCodec> {
block: Blocks,
tail: Tail,
}
impl<Blocks: BlockCodec, Tail: AnyLenCodec> Default for CompositeCodec<Blocks, Tail> {
fn default() -> Self {
Self::new(Blocks::default(), Tail::default())
}
}
impl<Blocks: BlockCodec, Tail: AnyLenCodec> CompositeCodec<Blocks, Tail> {
pub fn new(block: Blocks, tail: Tail) -> Self {
Self { block, tail }
}
}
impl<Blocks: BlockCodec, Tail: AnyLenCodec> AnyLenCodec for CompositeCodec<Blocks, Tail> {
fn encode(&mut self, input: &[u32], out: &mut Vec<u32>) -> FastPForResult<()> {
let (blocks, remainder) = slice_to_blocks::<Blocks>(input);
self.block.encode_blocks(blocks, out)?;
self.tail.encode(remainder, out)
}
fn decode(
&mut self,
input: &[u32],
out: &mut Vec<u32>,
expected_len: Option<u32>,
) -> FastPForResult<()> {
let start_len = out.len();
let max = Self::max_decompressed_len(input.len());
if let Some(expected) = expected_len {
out.reserve(expected.is_valid_expected(max)?);
}
if input.is_empty() {
self.tail.decode(&[], out, None)?;
return Ok(());
}
let block_expected = expected_len.map(|v| {
let v = (v.as_usize() / Blocks::size()) * Blocks::size();
u32::try_from(v).expect("block-aligned expected_len fits in u32")
});
let consumed = self.block.decode_blocks(input, block_expected, out)?;
let tail_input = &input[consumed..];
self.tail.decode(tail_input, out, None)?;
if let Some(n) = expected_len {
(out.len() - start_len).is_decoded_mismatch(n)?;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::rust::{FastPForBlock128, FastPForBlock256, JustCopy, VariableByte};
use crate::test_utils::{compress, decompress, roundtrip_composite, roundtrip_expected};
use crate::{FastPFor128, FastPFor256};
#[test]
fn test_fastpfor256_vbyte_exact_two_blocks() {
let data: Vec<u32> = (0..512).collect();
roundtrip_composite::<FastPForBlock256, VariableByte>(&data);
}
#[test]
fn test_fastpfor256_vbyte_with_remainder() {
let data: Vec<u32> = (0..600).collect();
roundtrip_composite::<FastPForBlock256, VariableByte>(&data);
}
#[test]
fn test_fastpfor128_justcopy_with_remainder() {
let data: Vec<u32> = (0..300).collect();
roundtrip_composite::<FastPForBlock128, JustCopy>(&data);
}
#[test]
fn test_empty_input() {
roundtrip_composite::<FastPForBlock256, VariableByte>(&[]);
}
#[test]
fn test_decode_truly_empty_input() {
assert!(decompress::<FastPFor256>(&[], None).unwrap().is_empty());
}
#[test]
fn test_decode_empty_input_with_expected_zero() {
assert!(decompress::<FastPFor256>(&[], Some(0)).unwrap().is_empty());
}
#[test]
fn test_empty_input_encodes_to_one_zero_word() {
let rust128 = compress::<FastPFor128>(&[]).unwrap();
assert_eq!(
rust128,
[0u32],
"FastPFor128: empty input must produce [0], got {rust128:?}"
);
let rust256 = compress::<FastPFor256>(&[]).unwrap();
assert_eq!(
rust256,
[0u32],
"FastPFor256: empty input must produce [0], got {rust256:?}"
);
#[cfg(feature = "cpp")]
{
use crate::cpp::{CppFastPFor128, CppFastPFor256};
let cpp128 = compress::<CppFastPFor128>(&[]).unwrap();
assert_eq!(
cpp128, rust128,
"CppFastPFor128 and FastPFor128 must agree on empty encoding"
);
let cpp256 = compress::<CppFastPFor256>(&[]).unwrap();
assert_eq!(
cpp256, rust256,
"CppFastPFor256 and FastPFor256 must agree on empty encoding"
);
}
}
#[test]
fn test_decode_empty_input_with_nonzero_expected_errors() {
decompress::<FastPFor256>(&[], Some(5)).unwrap_err();
}
#[test]
fn test_decode_huge_n_blocks_header_returns_error() {
let input = &[0x0019_3504u32]; decompress::<FastPFor256>(input, None).unwrap_err();
}
#[test]
fn test_sub_block_only() {
let data: Vec<u32> = (0..10).collect();
roundtrip_composite::<FastPForBlock256, VariableByte>(&data);
}
#[test]
fn test_decode_with_expected_len() {
let data: Vec<u32> = (0..600).collect();
roundtrip_expected::<FastPFor256>(&data, Some(600));
}
#[test]
fn test_decode_expected_len_mismatch_errors() {
let data: Vec<u32> = (0..100).collect();
let encoded = compress::<FastPFor256>(&data).unwrap();
decompress::<FastPFor256>(&encoded, Some(50)).unwrap_err();
}
#[test]
fn test_decode_expected_len_exceeds_max_errors() {
let data: Vec<u32> = (0..10).collect();
let encoded = compress::<FastPFor256>(&data).unwrap();
let huge = (FastPFor256::max_decompressed_len(encoded.len()) + 1) as u32;
decompress::<FastPFor256>(&encoded, Some(huge)).unwrap_err();
}
}