use crate::range_decoder::RangeDecoder;
pub const ALLOC_TRIM_PDF_LEN: usize = 11;
pub const ALLOC_TRIM_FTB: u32 = 7;
pub const ALLOC_TRIM_PDF_DENOMINATOR: u32 = 1 << ALLOC_TRIM_FTB;
pub const ALLOC_TRIM_DEFAULT: u8 = 5;
pub const ALLOC_TRIM_MIN: u8 = 0;
pub const ALLOC_TRIM_MAX: u8 = 10;
pub const ALLOC_TRIM_SIGNAL_COST_EIGHTH_BITS: u32 = 48;
pub const EIGHTH_BITS_PER_BYTE: u32 = 64;
pub const ALLOC_TRIM_PDF: [u8; ALLOC_TRIM_PDF_LEN] = [2, 2, 5, 10, 22, 46, 22, 10, 5, 2, 2];
pub const ALLOC_TRIM_ICDF: [u8; ALLOC_TRIM_PDF_LEN] = [126, 124, 119, 109, 87, 41, 19, 9, 4, 2, 0];
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AllocTrimError {
FrameSizeOverflows,
TotalBoostExceedsFrame {
frame_eighth_bits: u32,
total_boost: u32,
},
}
pub const fn alloc_trim_is_signalled(
ec_tell_frac: u32,
frame_eighth_bits: u32,
total_boost: u32,
) -> bool {
let budget = match frame_eighth_bits.checked_sub(total_boost) {
Some(b) => b,
None => return false,
};
match ec_tell_frac.checked_add(ALLOC_TRIM_SIGNAL_COST_EIGHTH_BITS) {
Some(consumed_after) => consumed_after <= budget,
None => false,
}
}
pub const fn frame_eighth_bits(frame_size_bytes: u32) -> Result<u32, AllocTrimError> {
match frame_size_bytes.checked_mul(EIGHTH_BITS_PER_BYTE) {
Some(v) => Ok(v),
None => Err(AllocTrimError::FrameSizeOverflows),
}
}
pub fn decode_alloc_trim(
rd: &mut RangeDecoder<'_>,
ec_tell_frac: u32,
frame_size_bytes: u32,
total_boost: u32,
) -> Result<u8, AllocTrimError> {
let frame_eighth = frame_eighth_bits(frame_size_bytes)?;
if total_boost > frame_eighth {
return Err(AllocTrimError::TotalBoostExceedsFrame {
frame_eighth_bits: frame_eighth,
total_boost,
});
}
if !alloc_trim_is_signalled(ec_tell_frac, frame_eighth, total_boost) {
return Ok(ALLOC_TRIM_DEFAULT);
}
let symbol = rd.dec_icdf(&ALLOC_TRIM_ICDF, ALLOC_TRIM_FTB);
Ok(symbol as u8)
}
pub const fn alloc_trim_icdf() -> &'static [u8; ALLOC_TRIM_PDF_LEN] {
&ALLOC_TRIM_ICDF
}
pub const fn alloc_trim_pdf() -> &'static [u8; ALLOC_TRIM_PDF_LEN] {
&ALLOC_TRIM_PDF
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn pdf_length_constant_matches_array() {
assert_eq!(ALLOC_TRIM_PDF_LEN, 11);
assert_eq!(ALLOC_TRIM_PDF.len(), ALLOC_TRIM_PDF_LEN);
assert_eq!(ALLOC_TRIM_ICDF.len(), ALLOC_TRIM_PDF_LEN);
}
#[test]
fn ftb_constant_is_seven_for_denominator_128() {
assert_eq!(ALLOC_TRIM_FTB, 7);
assert_eq!(ALLOC_TRIM_PDF_DENOMINATOR, 128);
assert_eq!(1u32 << ALLOC_TRIM_FTB, ALLOC_TRIM_PDF_DENOMINATOR);
}
#[test]
fn trim_range_constants_match_rfc() {
assert_eq!(ALLOC_TRIM_MIN, 0);
assert_eq!(ALLOC_TRIM_MAX, 10);
assert_eq!(
(ALLOC_TRIM_MAX - ALLOC_TRIM_MIN + 1) as usize,
ALLOC_TRIM_PDF_LEN
);
}
#[test]
fn default_trim_constant_matches_rfc() {
assert_eq!(ALLOC_TRIM_DEFAULT, 5);
}
#[test]
fn signal_cost_constant_matches_rfc() {
assert_eq!(ALLOC_TRIM_SIGNAL_COST_EIGHTH_BITS, 48);
assert_eq!(ALLOC_TRIM_SIGNAL_COST_EIGHTH_BITS / 8, 6);
}
#[test]
fn eighth_bits_per_byte_constant_is_sixty_four() {
assert_eq!(EIGHTH_BITS_PER_BYTE, 64);
}
#[test]
fn pdf_cells_match_table_58() {
assert_eq!(ALLOC_TRIM_PDF, [2u8, 2, 5, 10, 22, 46, 22, 10, 5, 2, 2]);
}
#[test]
fn pdf_sums_to_denominator() {
let sum: u32 = ALLOC_TRIM_PDF.iter().map(|&c| c as u32).sum();
assert_eq!(sum, ALLOC_TRIM_PDF_DENOMINATOR);
}
#[test]
fn pdf_is_symmetric_around_default() {
let n = ALLOC_TRIM_PDF.len();
for k in 0..n {
assert_eq!(
ALLOC_TRIM_PDF[k],
ALLOC_TRIM_PDF[n - 1 - k],
"PDF not symmetric at k={}",
k
);
}
}
#[test]
fn default_cell_has_heaviest_mass() {
let max_idx = ALLOC_TRIM_PDF
.iter()
.enumerate()
.max_by_key(|(_, &v)| v)
.map(|(k, _)| k)
.expect("non-empty PDF");
assert_eq!(max_idx, ALLOC_TRIM_DEFAULT as usize);
assert_eq!(ALLOC_TRIM_PDF[max_idx], 46);
}
#[test]
fn icdf_matches_pdf_derivation() {
let mut fh: u32 = 0;
for (k, &pmf) in ALLOC_TRIM_PDF.iter().enumerate() {
fh += pmf as u32;
let derived = ALLOC_TRIM_PDF_DENOMINATOR - fh;
assert_eq!(
ALLOC_TRIM_ICDF[k] as u32, derived,
"iCDF/PDF mismatch at k={}",
k
);
}
assert_eq!(fh, ALLOC_TRIM_PDF_DENOMINATOR);
assert_eq!(ALLOC_TRIM_ICDF[ALLOC_TRIM_PDF_LEN - 1], 0);
}
#[test]
fn icdf_is_strictly_monotone_decreasing() {
for w in ALLOC_TRIM_ICDF.windows(2) {
assert!(w[0] > w[1], "iCDF not strictly decreasing at pair {:?}", w);
}
}
#[test]
fn icdf_spot_cells_pinned() {
assert_eq!(ALLOC_TRIM_ICDF[0], 126); assert_eq!(ALLOC_TRIM_ICDF[1], 124); assert_eq!(ALLOC_TRIM_ICDF[5], 41); assert_eq!(ALLOC_TRIM_ICDF[10], 0); }
#[test]
fn pdf_borrow_returns_full_table() {
assert_eq!(alloc_trim_pdf(), &ALLOC_TRIM_PDF);
}
#[test]
fn icdf_borrow_returns_full_table() {
assert_eq!(alloc_trim_icdf(), &ALLOC_TRIM_ICDF);
}
#[test]
fn frame_eighth_bits_scales_by_sixty_four() {
assert_eq!(frame_eighth_bits(0).unwrap(), 0);
assert_eq!(frame_eighth_bits(1).unwrap(), 64);
assert_eq!(frame_eighth_bits(1275).unwrap(), 1275 * 64);
}
#[test]
fn frame_eighth_bits_rejects_overflow() {
let boundary = u32::MAX / EIGHTH_BITS_PER_BYTE;
assert!(frame_eighth_bits(boundary).is_ok());
assert_eq!(
frame_eighth_bits(boundary + 1).unwrap_err(),
AllocTrimError::FrameSizeOverflows
);
assert_eq!(
frame_eighth_bits(u32::MAX).unwrap_err(),
AllocTrimError::FrameSizeOverflows
);
}
#[test]
fn gate_passes_when_room_for_signal_cost() {
assert!(alloc_trim_is_signalled(100, 3840, 0));
}
#[test]
fn gate_fails_when_no_room() {
let frame = 3840;
assert!(!alloc_trim_is_signalled(frame - 47, frame, 0));
assert!(alloc_trim_is_signalled(frame - 48, frame, 0));
}
#[test]
fn gate_subtracts_total_boost_from_budget() {
assert!(!alloc_trim_is_signalled(3700, 3840, 100));
assert!(alloc_trim_is_signalled(3691, 3840, 100));
}
#[test]
fn gate_handles_underflow_safely() {
assert!(!alloc_trim_is_signalled(0, 100, 200));
}
#[test]
fn gate_handles_ec_tell_frac_addition_overflow_safely() {
assert!(!alloc_trim_is_signalled(u32::MAX, 3840, 0));
}
#[test]
fn gate_at_six_bit_boundary() {
assert!(alloc_trim_is_signalled(80, 128, 0));
assert!(!alloc_trim_is_signalled(81, 128, 0));
}
fn rd<'a>(buf: &'a [u8]) -> RangeDecoder<'a> {
RangeDecoder::new(buf)
}
#[test]
fn decode_returns_default_when_gate_fails() {
let buf = [0x80u8];
let mut d = rd(&buf);
let trim = decode_alloc_trim(&mut d, 9, 1, 20).unwrap();
assert_eq!(trim, ALLOC_TRIM_DEFAULT);
}
#[test]
fn decode_consumes_no_bits_when_gate_fails() {
let buf = [0x80u8];
let mut d = rd(&buf);
let before = d.tell();
let _ = decode_alloc_trim(&mut d, 9, 1, 20).unwrap();
assert_eq!(d.tell(), before);
}
#[test]
fn decode_returns_in_range_value_when_gate_passes() {
let buf = [0x00u8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
let mut d = rd(&buf);
let frac = d.tell_frac();
let trim = decode_alloc_trim(&mut d, frac, 8, 0).unwrap();
assert!(trim <= ALLOC_TRIM_MAX, "trim {} out of range", trim);
}
#[test]
fn decode_consumes_range_bits_when_gate_passes() {
let buf = [0x00u8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
let mut d = rd(&buf);
let before_frac = d.tell_frac();
let _ = decode_alloc_trim(&mut d, before_frac, 8, 0).unwrap();
assert!(d.tell_frac() >= before_frac);
assert!(d.tell_frac() > before_frac);
}
#[test]
fn decode_rejects_frame_size_overflow() {
let buf = [0x80u8];
let mut d = rd(&buf);
let err = decode_alloc_trim(&mut d, 0, u32::MAX, 0).unwrap_err();
assert_eq!(err, AllocTrimError::FrameSizeOverflows);
}
#[test]
fn decode_rejects_boost_exceeding_frame() {
let buf = [0x80u8];
let mut d = rd(&buf);
let err = decode_alloc_trim(&mut d, 0, 1, 100).unwrap_err();
assert_eq!(
err,
AllocTrimError::TotalBoostExceedsFrame {
frame_eighth_bits: 64,
total_boost: 100,
}
);
}
#[test]
fn decode_does_not_consume_bits_on_error_paths() {
let buf = [0x80u8];
let mut d = rd(&buf);
let before_frac = d.tell_frac();
let _ = decode_alloc_trim(&mut d, 0, u32::MAX, 0);
assert_eq!(d.tell_frac(), before_frac);
let _ = decode_alloc_trim(&mut d, 0, 1, 100);
assert_eq!(d.tell_frac(), before_frac);
}
#[test]
fn every_pdf_index_is_a_valid_trim_value() {
for k in 0..ALLOC_TRIM_PDF_LEN as u8 {
assert!((ALLOC_TRIM_MIN..=ALLOC_TRIM_MAX).contains(&k));
}
}
#[test]
fn pdf_index_count_equals_trim_value_count() {
let trim_value_count = (ALLOC_TRIM_MAX - ALLOC_TRIM_MIN) as usize + 1;
assert_eq!(trim_value_count, ALLOC_TRIM_PDF_LEN);
}
#[test]
fn worst_case_symbol_cost_matches_gate_budget() {
let min_mass: u32 = *ALLOC_TRIM_PDF.iter().min().unwrap() as u32;
let denominator = ALLOC_TRIM_PDF_DENOMINATOR;
assert_eq!(min_mass, 2);
let bits = (denominator / min_mass).trailing_zeros();
assert_eq!(bits, 6);
assert_eq!(bits * 8, ALLOC_TRIM_SIGNAL_COST_EIGHTH_BITS);
}
}