use alloc::vec::Vec;
pub fn ll_code(value: u32) -> (u8, u32, u32) {
if value < 16 {
return (value as u8, 0, 0);
}
let bases: [u32; 36] = [
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 22, 24, 28, 32, 40, 48,
64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536,
];
let extras: [u32; 36] = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 4, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16,
];
for c in (16..36).rev() {
if value >= bases[c] {
let extra_val = value - bases[c];
debug_assert!(extras[c] == 0 || extra_val < (1u32 << extras[c]));
return (c as u8, extras[c], extra_val);
}
}
(35, extras[35], value - bases[35])
}
pub fn ml_code(value: u32) -> (u8, u32, u32) {
if value < 3 {
return (0, 0, 0);
}
if value < 35 {
let code = (value - 3) as u8;
return (code, 0, 0);
}
let bases: [u32; 53] = [
3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 39, 41, 43, 47, 51, 59, 67, 83, 99, 131, 259, 515,
1027, 2051, 4099, 8195, 16387, 32771, 65539,
];
let extras: [u32; 53] = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
];
for c in (32..53).rev() {
if value >= bases[c] {
let extra_val = value - bases[c];
debug_assert!(extras[c] == 0 || extra_val < (1u32 << extras[c]));
return (c as u8, extras[c], extra_val);
}
}
(52, extras[52], value - bases[52])
}
pub fn of_code(offset_value: u32) -> (u8, u32, u32) {
if offset_value == 0 {
return (0, 0, 0);
}
let code = 31 - offset_value.leading_zeros();
let base = 1u32 << code;
(code as u8, code, offset_value - base)
}
pub fn encode_sequence_count(count: u32) -> Vec<u8> {
let mut out = Vec::with_capacity(3);
if count < 128 {
out.push(count as u8);
} else if count < 0x7F00 {
let b0 = ((count >> 8) | 0x80) as u8;
let b1 = (count & 0xFF) as u8;
out.push(b0);
out.push(b1);
} else {
let v = count - 0x7F00;
out.push(0xFF);
out.push((v & 0xFF) as u8);
out.push(((v >> 8) & 0xFF) as u8);
}
out
}
#[cfg(test)]
mod tests {
use super::*;
fn ll_decode(code: u8, extra_val: u32) -> u32 {
let bases: [u32; 36] = [
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 22, 24, 28, 32, 40,
48, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536,
];
bases[code as usize] + extra_val
}
fn ml_decode(code: u8, extra_val: u32) -> u32 {
let bases: [u32; 53] = [
3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 39, 41, 43, 47, 51, 59, 67, 83, 99, 131,
259, 515, 1027, 2051, 4099, 8195, 16387, 32771, 65539,
];
bases[code as usize] + extra_val
}
#[test]
fn ll_round_trip_small() {
for v in 0..=15u32 {
let (code, _extra_bits, extra_val) = ll_code(v);
assert_eq!(ll_decode(code, extra_val), v);
}
}
#[test]
fn ll_round_trip_medium() {
for v in [16u32, 17, 18, 23, 24, 100, 500, 4096, 65535] {
let (code, _eb, ev) = ll_code(v);
assert_eq!(ll_decode(code, ev), v, "v={}", v);
}
}
#[test]
fn ml_round_trip() {
for v in [3u32, 4, 10, 34, 35, 36, 100, 500, 65538] {
let (code, _eb, ev) = ml_code(v);
assert_eq!(ml_decode(code, ev), v, "v={}", v);
}
}
#[test]
fn of_round_trip() {
for ov in [1u32, 2, 3, 4, 5, 100, 1024, 65536] {
let (code, _eb, ev) = of_code(ov);
let decoded = if code == 0 { 1 } else { (1u32 << code) + ev };
assert_eq!(decoded, ov, "ov={}", ov);
}
}
#[test]
fn n_seq_round_trip() {
for &n in &[0u32, 1, 127, 128, 255, 1000, 32639, 32640, 70000] {
let encoded = encode_sequence_count(n);
let b0 = encoded[0];
let v = if b0 == 0 {
0u32
} else if b0 < 128 {
b0 as u32
} else if b0 < 255 {
(((b0 as u32) - 128) << 8) | (encoded[1] as u32)
} else {
((encoded[1] as u32) | ((encoded[2] as u32) << 8)) + 0x7F00
};
assert_eq!(v, n, "round-trip failed for n={}", n);
}
}
}