extern crate alloc;
use alloc::vec;
use alloc::vec::Vec;
use crate::error::Error;
use super::bits::BitReader;
pub(crate) const MAX_CODE_LENGTH: u32 = 32;
const NONE: u32 = u32::MAX;
pub(crate) struct Huffman {
links: Vec<u32>,
leaf: Vec<u32>,
}
impl Huffman {
pub(crate) fn from_lengths(lengths: &[u8]) -> Result<Self, Error> {
let mut counts = [0u32; MAX_CODE_LENGTH as usize + 1];
let mut max_len = 0u32;
for &l in lengths {
let l = l as u32;
if l > MAX_CODE_LENGTH {
return Err(Error::InvalidHuffmanTree);
}
if l > 0 {
counts[l as usize] += 1;
if l > max_len {
max_len = l;
}
}
}
if max_len == 0 {
return Ok(Self::empty());
}
let mut kraft: u64 = 0;
for l in 1..=max_len {
kraft += (counts[l as usize] as u64) << (max_len - l);
}
let full: u64 = 1u64 << max_len;
if kraft > full {
return Err(Error::InvalidHuffmanTree);
}
if kraft != full {
return Err(Error::InvalidHuffmanTree);
}
let mut next_code = [0u32; MAX_CODE_LENGTH as usize + 1];
let mut code: u32 = 0;
for l in 1..=max_len {
next_code[l as usize] = code;
code = (code + counts[l as usize]) << 1;
}
let mut builder = TrieBuilder::new();
for (sym, &l8) in lengths.iter().enumerate() {
let l = l8 as u32;
if l == 0 {
continue;
}
let msb_code = next_code[l as usize];
next_code[l as usize] += 1;
let lsb_code = reverse_bits(msb_code, l);
builder.insert(lsb_code, l, sym as u32)?;
}
Ok(builder.finish())
}
pub(crate) fn from_codes(values: &[u32], lengths: &[u8]) -> Result<Self, Error> {
if values.len() != lengths.len() {
return Err(Error::InvalidHuffmanTree);
}
let mut builder = TrieBuilder::new();
for (sym, (&v, &l8)) in values.iter().zip(lengths.iter()).enumerate() {
let l = l8 as u32;
if l == 0 {
continue;
}
if l > MAX_CODE_LENGTH {
return Err(Error::InvalidHuffmanTree);
}
builder.insert(v, l, sym as u32)?;
}
Ok(builder.finish())
}
fn empty() -> Self {
Self {
links: vec![NONE, NONE],
leaf: vec![NONE],
}
}
pub(crate) fn decode(&self, reader: &mut BitReader<'_>) -> Result<u32, Error> {
let mut node: u32 = 0;
loop {
if self.leaf[node as usize] != NONE {
return Ok(self.leaf[node as usize]);
}
let bit = reader.read_bit()?;
let next = self.links[(node as usize) * 2 + bit as usize];
if next == NONE {
return Err(Error::InvalidHuffmanTree);
}
node = next;
}
}
}
fn reverse_bits(v: u32, n: u32) -> u32 {
let mut out = 0u32;
for i in 0..n {
out |= ((v >> i) & 1) << (n - 1 - i);
}
out
}
struct TrieBuilder {
links: Vec<u32>,
leaf: Vec<u32>,
}
impl TrieBuilder {
fn new() -> Self {
Self {
links: vec![NONE, NONE],
leaf: vec![NONE],
}
}
fn insert(&mut self, code: u32, len: u32, sym: u32) -> Result<(), Error> {
let mut node: u32 = 0;
for i in 0..len {
if self.leaf[node as usize] != NONE {
return Err(Error::InvalidHuffmanTree);
}
let bit = ((code >> i) & 1) as usize;
let slot = (node as usize) * 2 + bit;
if self.links[slot] == NONE {
let new_idx = self.leaf.len() as u32;
self.links.push(NONE);
self.links.push(NONE);
self.leaf.push(NONE);
self.links[slot] = new_idx;
}
node = self.links[slot];
}
if self.leaf[node as usize] != NONE
|| self.links[(node as usize) * 2] != NONE
|| self.links[(node as usize) * 2 + 1] != NONE
{
return Err(Error::InvalidHuffmanTree);
}
self.leaf[node as usize] = sym;
Ok(())
}
fn finish(self) -> Huffman {
Huffman {
links: self.links,
leaf: self.leaf,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn reverse_bits_works() {
assert_eq!(reverse_bits(0b001, 3), 0b100);
assert_eq!(reverse_bits(0b10, 2), 0b01);
assert_eq!(reverse_bits(0, 5), 0);
}
#[test]
fn canonical_lsb_roundtrip() {
let h = Huffman::from_lengths(&[1, 2, 2]).unwrap();
let data = [0x1Au8];
let mut r = BitReader::new(&data);
assert_eq!(h.decode(&mut r).unwrap(), 0);
assert_eq!(h.decode(&mut r).unwrap(), 1);
assert_eq!(h.decode(&mut r).unwrap(), 2);
}
#[test]
fn metacode_builds_and_decodes() {
let h = Huffman::from_codes(
&super::super::tables::META_CODE_VALUES,
&super::super::tables::META_CODE_LENGTHS,
)
.unwrap();
let data = [0b0000_0001u8];
let mut r = BitReader::new(&data);
assert_eq!(h.decode(&mut r).unwrap(), 32);
}
#[test]
fn rejects_oversubscribed() {
assert!(matches!(
Huffman::from_lengths(&[1, 1, 1]),
Err(Error::InvalidHuffmanTree)
));
}
#[test]
fn rejects_undersubscribed() {
assert!(matches!(
Huffman::from_lengths(&[2]),
Err(Error::InvalidHuffmanTree)
));
}
#[test]
fn rejects_length_over_cap() {
let mut lens = [0u8; 2];
lens[0] = 33;
assert!(matches!(
Huffman::from_lengths(&lens),
Err(Error::InvalidHuffmanTree)
));
}
#[test]
fn empty_decode_errors() {
let h = Huffman::from_lengths(&[0, 0, 0]).unwrap();
let data = [0xFFu8];
let mut r = BitReader::new(&data);
assert!(matches!(h.decode(&mut r), Err(Error::InvalidHuffmanTree)));
}
#[test]
fn all_predefined_sets_build() {
for s in 0..5 {
Huffman::from_lengths(super::super::tables::PREDEFINED_FIRST[s]).unwrap();
Huffman::from_lengths(super::super::tables::PREDEFINED_SECOND[s]).unwrap();
Huffman::from_lengths(super::super::tables::PREDEFINED_OFFSET[s]).unwrap();
}
}
}