#![forbid(unsafe_code)]
use crate::core::representation::RansCodec;
use crate::rans::model::RansModel;
use crate::rans::residual::{RansStreamError, decode_stream, encode_stream};
#[derive(Debug, Clone, Copy, PartialEq, Eq, clap::ValueEnum)]
pub enum Backend {
ScalarSingle,
ScalarInterleaved2,
}
impl Backend {
pub const fn authority() -> Self {
Self::ScalarInterleaved2
}
pub const fn codec(self) -> RansCodec {
match self {
Backend::ScalarSingle => RansCodec::Single,
Backend::ScalarInterleaved2 => RansCodec::Interleaved2,
}
}
pub fn available(self) -> bool {
true
}
}
impl std::fmt::Display for Backend {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{self:?}")
}
}
pub fn encode_with_backend(
input: &[u8],
model: &RansModel,
backend: Backend,
) -> Result<Vec<u8>, RansStreamError> {
if model.codec != backend.codec() {
return Err(RansStreamError::Model("backend/codec mismatch".into()));
}
encode_stream(input, model)
}
pub fn decode(encoded: &[u8], model: &RansModel, out_len: u64) -> Result<Vec<u8>, RansStreamError> {
decode_stream(model, encoded, out_len)
}
pub fn active_backend() -> Backend {
Backend::authority()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::rans::model::normalize_histogram;
fn hist_of(data: &[u8]) -> [u32; 256] {
let mut h = [0u32; 256];
for &b in data {
h[b as usize] += 1;
}
h
}
#[test]
fn authority_roundtrip() {
let data: Vec<u8> = (0..10000u32).map(|i| ((i * 7) % 41) as u8).collect();
let model = normalize_histogram(&hist_of(&data), 14, Backend::authority().codec()).unwrap();
let encoded = encode_with_backend(&data, &model, Backend::authority()).unwrap();
let decoded = decode(&encoded, &model, data.len() as u64).unwrap();
assert_eq!(decoded, data);
}
#[test]
fn backend_codec_mismatch_rejected() {
let data = b"abc".to_vec();
let model = normalize_histogram(&hist_of(&data), 14, RansCodec::Interleaved2).unwrap();
assert!(encode_with_backend(&data, &model, Backend::ScalarSingle).is_err());
}
}