use crate::{
bitpack::{bitunpack_into, packed_byte_size},
constants::AlpFloat,
encoder::ALP_MAGIC,
error::{Error, Result},
};
pub fn decompress_into<F: AlpFloat>(src: &[u8], dst: &mut Vec<F>) -> Result<()> {
if src.len() < 8 {
return Err(Error::UnexpectedEof {
needed: 8,
available: src.len(),
});
}
if src[0..2] != ALP_MAGIC || src[2] != F::TYPE_BYTE {
return Err(Error::InvalidHeader);
}
let count = u16::from_le_bytes([src[3], src[4]]) as usize;
let exp = src[5];
let fac = src[6];
let bit_width = src[7];
if exp > F::MAX_EXPONENT || fac > F::MAX_FAC || fac > exp || bit_width > F::MAX_BIT_WIDTH {
return Err(Error::UnsupportedParams {
exp,
fac,
bit_width,
});
}
let mut cursor = 8;
if count == 0 {
return Ok(());
}
if src.len() < cursor + F::BASE_SIZE {
return Err(Error::UnexpectedEof {
needed: cursor + F::BASE_SIZE,
available: src.len(),
});
}
let base = F::read_base(&src[cursor..cursor + F::BASE_SIZE]);
cursor += F::BASE_SIZE;
let packed_len = packed_byte_size(count, bit_width);
if src.len() < cursor + packed_len + 2 {
return Err(Error::UnexpectedEof {
needed: cursor + packed_len + 2,
available: src.len(),
});
}
let start_idx = dst.len();
let fac_int = F::fac_int(fac);
let frac_flt = F::frac_exp(exp);
bitunpack_into(
&src[cursor..cursor + packed_len],
count,
bit_width,
base,
fac_int,
frac_flt,
dst,
)?;
cursor += packed_len;
let exc_count = u16::from_le_bytes([src[cursor], src[cursor + 1]]) as usize;
cursor += 2;
let exc_bytes_needed = exc_count * F::EXC_ENTRY_SIZE;
if src.len() < cursor + exc_bytes_needed {
return Err(Error::UnexpectedEof {
needed: cursor + exc_bytes_needed,
available: src.len(),
});
}
for _ in 0..exc_count {
let (pos, val) = F::read_exception(&src[cursor..cursor + F::EXC_ENTRY_SIZE]);
cursor += F::EXC_ENTRY_SIZE;
if pos >= count {
return Err(Error::CorruptedData { index: pos, count });
}
unsafe {
*dst.get_unchecked_mut(start_idx + pos) = val;
}
}
Ok(())
}
#[inline]
pub fn decompress<F: AlpFloat>(src: &[u8]) -> Result<Vec<F>> {
let mut dst = Vec::new();
decompress_into(src, &mut dst)?;
Ok(dst)
}