use fastpfor::{AnyLenCodec as _, FastPFor256};
use usize_cast::IntoUsize as _;
use crate::{Decoder, MltError, MltResult};
pub fn decode_fastpfor(data: &[u8], num_values: u32, dec: &mut Decoder) -> MltResult<Vec<u32>> {
if num_values == 0 {
return if data.is_empty() {
Ok(vec![])
} else {
Err(MltError::InvalidFastPforByteLength(0))
};
}
if !data.len().is_multiple_of(4) {
return Err(MltError::InvalidFastPforByteLength(data.len()));
}
let num_words = data.len() / 4;
dec.consume_items::<u32>(num_words)?;
let input: Vec<u32> = (0..num_words)
.map(|i| {
let o = i * 4;
u32::from_be_bytes([data[o], data[o + 1], data[o + 2], data[o + 3]])
})
.collect();
let mut result = Vec::new();
FastPFor256::default().decode(&input, &mut result, Some(num_values))?;
let Some(adjustment) = result
.len()
.checked_sub(num_values.into_usize())
.and_then(|v| u32::try_from(v).ok())
else {
return Err(MltError::FastPforDecode(num_values, result.len()));
};
dec.adjust(adjustment);
result.truncate(num_values.into_usize());
Ok(result)
}
#[cfg(test)]
mod tests {
use proptest::prelude::*;
use super::*;
use crate::test_helpers::dec;
proptest! {
#[test]
fn test_fastpfor_roundtrip(data: Vec<u32>) {
prop_assume!(!data.is_empty());
let mut encoded = Vec::new();
FastPFor256::default().encode(&data, &mut encoded).unwrap();
let mut encoded2 = Vec::with_capacity(encoded.len() * 4);
for word in &encoded {
encoded2.extend_from_slice(&word.to_be_bytes());
}
let decoded = decode_fastpfor(&encoded2, data.len().try_into().unwrap(), &mut dec()).unwrap();
prop_assert_eq!(data, decoded);
}
}
#[test]
fn test_decode_fastpfor_empty() {
let decoded = decode_fastpfor(&[], 0, &mut dec()).unwrap();
assert!(decoded.is_empty());
}
}