use std::fmt;
use std::sync::OnceLock;
use bytes::Bytes;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Symbol {
pub code: u32,
pub length: u8,
}
impl Symbol {
pub const fn new(code: u32, length: u8) -> Self {
Self { code, length }
}
}
pub const EOS: u16 = 256;
pub static TABLE: [Symbol; 257] = [
Symbol::new(0x1ff8, 13), Symbol::new(0x7fffd8, 23), Symbol::new(0xfffffe2, 28), Symbol::new(0xfffffe3, 28), Symbol::new(0xfffffe4, 28), Symbol::new(0xfffffe5, 28), Symbol::new(0xfffffe6, 28), Symbol::new(0xfffffe7, 28), Symbol::new(0xfffffe8, 28), Symbol::new(0xffffea, 24), Symbol::new(0x3ffffffc, 30), Symbol::new(0xfffffe9, 28), Symbol::new(0xfffffea, 28), Symbol::new(0x3ffffffd, 30), Symbol::new(0xfffffeb, 28), Symbol::new(0xfffffec, 28), Symbol::new(0xfffffed, 28), Symbol::new(0xfffffee, 28), Symbol::new(0xfffffef, 28), Symbol::new(0xffffff0, 28), Symbol::new(0xffffff1, 28), Symbol::new(0xffffff2, 28), Symbol::new(0x3ffffffe, 30), Symbol::new(0xffffff3, 28), Symbol::new(0xffffff4, 28), Symbol::new(0xffffff5, 28), Symbol::new(0xffffff6, 28), Symbol::new(0xffffff7, 28), Symbol::new(0xffffff8, 28), Symbol::new(0xffffff9, 28), Symbol::new(0xffffffa, 28), Symbol::new(0xffffffb, 28), Symbol::new(0x14, 6), Symbol::new(0x3f8, 10), Symbol::new(0x3f9, 10), Symbol::new(0xffa, 12), Symbol::new(0x1ff9, 13), Symbol::new(0x15, 6), Symbol::new(0xf8, 8), Symbol::new(0x7fa, 11), Symbol::new(0x3fa, 10), Symbol::new(0x3fb, 10), Symbol::new(0xf9, 8), Symbol::new(0x7fb, 11), Symbol::new(0xfa, 8), Symbol::new(0x16, 6), Symbol::new(0x17, 6), Symbol::new(0x18, 6), Symbol::new(0x0, 5), Symbol::new(0x1, 5), Symbol::new(0x2, 5), Symbol::new(0x19, 6), Symbol::new(0x1a, 6), Symbol::new(0x1b, 6), Symbol::new(0x1c, 6), Symbol::new(0x1d, 6), Symbol::new(0x1e, 6), Symbol::new(0x1f, 6), Symbol::new(0x5c, 7), Symbol::new(0xfb, 8), Symbol::new(0x7ffc, 15), Symbol::new(0x20, 6), Symbol::new(0xffb, 12), Symbol::new(0x3fc, 10), Symbol::new(0x1ffa, 13), Symbol::new(0x21, 6), Symbol::new(0x5d, 7), Symbol::new(0x5e, 7), Symbol::new(0x5f, 7), Symbol::new(0x60, 7), Symbol::new(0x61, 7), Symbol::new(0x62, 7), Symbol::new(0x63, 7), Symbol::new(0x64, 7), Symbol::new(0x65, 7), Symbol::new(0x66, 7), Symbol::new(0x67, 7), Symbol::new(0x68, 7), Symbol::new(0x69, 7), Symbol::new(0x6a, 7), Symbol::new(0x6b, 7), Symbol::new(0x6c, 7), Symbol::new(0x6d, 7), Symbol::new(0x6e, 7), Symbol::new(0x6f, 7), Symbol::new(0x70, 7), Symbol::new(0x71, 7), Symbol::new(0x72, 7), Symbol::new(0xfc, 8), Symbol::new(0x73, 7), Symbol::new(0xfd, 8), Symbol::new(0x1ffb, 13), Symbol::new(0x7fff0, 19), Symbol::new(0x1ffc, 13), Symbol::new(0x3ffc, 14), Symbol::new(0x22, 6), Symbol::new(0x7ffd, 15), Symbol::new(0x3, 5), Symbol::new(0x23, 6), Symbol::new(0x4, 5), Symbol::new(0x24, 6), Symbol::new(0x5, 5), Symbol::new(0x25, 6), Symbol::new(0x26, 6), Symbol::new(0x27, 6), Symbol::new(0x6, 5), Symbol::new(0x74, 7), Symbol::new(0x75, 7), Symbol::new(0x28, 6), Symbol::new(0x29, 6), Symbol::new(0x2a, 6), Symbol::new(0x7, 5), Symbol::new(0x2b, 6), Symbol::new(0x76, 7), Symbol::new(0x2c, 6), Symbol::new(0x8, 5), Symbol::new(0x9, 5), Symbol::new(0x2d, 6), Symbol::new(0x77, 7), Symbol::new(0x78, 7), Symbol::new(0x79, 7), Symbol::new(0x7a, 7), Symbol::new(0x7b, 7), Symbol::new(0x7ffe, 15), Symbol::new(0x7fc, 11), Symbol::new(0x3ffd, 14), Symbol::new(0x1ffd, 13), Symbol::new(0xffffffc, 28), Symbol::new(0xfffe6, 20), Symbol::new(0x3fffd2, 22), Symbol::new(0xfffe7, 20), Symbol::new(0xfffe8, 20), Symbol::new(0x3fffd3, 22), Symbol::new(0x3fffd4, 22), Symbol::new(0x3fffd5, 22), Symbol::new(0x7fffd9, 23), Symbol::new(0x3fffd6, 22), Symbol::new(0x7fffda, 23), Symbol::new(0x7fffdb, 23), Symbol::new(0x7fffdc, 23), Symbol::new(0x7fffdd, 23), Symbol::new(0x7fffde, 23), Symbol::new(0xffffeb, 24), Symbol::new(0x7fffdf, 23), Symbol::new(0xffffec, 24), Symbol::new(0xffffed, 24), Symbol::new(0x3fffd7, 22), Symbol::new(0x7fffe0, 23), Symbol::new(0xffffee, 24), Symbol::new(0x7fffe1, 23), Symbol::new(0x7fffe2, 23), Symbol::new(0x7fffe3, 23), Symbol::new(0x7fffe4, 23), Symbol::new(0x1fffdc, 21), Symbol::new(0x3fffd8, 22), Symbol::new(0x7fffe5, 23), Symbol::new(0x3fffd9, 22), Symbol::new(0x7fffe6, 23), Symbol::new(0x7fffe7, 23), Symbol::new(0xffffef, 24), Symbol::new(0x3fffda, 22), Symbol::new(0x1fffdd, 21), Symbol::new(0xfffe9, 20), Symbol::new(0x3fffdb, 22), Symbol::new(0x3fffdc, 22), Symbol::new(0x7fffe8, 23), Symbol::new(0x7fffe9, 23), Symbol::new(0x1fffde, 21), Symbol::new(0x7fffea, 23), Symbol::new(0x3fffdd, 22), Symbol::new(0x3fffde, 22), Symbol::new(0xfffff0, 24), Symbol::new(0x1fffdf, 21), Symbol::new(0x3fffdf, 22), Symbol::new(0x7fffeb, 23), Symbol::new(0x7fffec, 23), Symbol::new(0x1fffe0, 21), Symbol::new(0x1fffe1, 21), Symbol::new(0x3fffe0, 22), Symbol::new(0x1fffe2, 21), Symbol::new(0x7fffed, 23), Symbol::new(0x3fffe1, 22), Symbol::new(0x7fffee, 23), Symbol::new(0x7fffef, 23), Symbol::new(0xfffea, 20), Symbol::new(0x3fffe2, 22), Symbol::new(0x3fffe3, 22), Symbol::new(0x3fffe4, 22), Symbol::new(0x7ffff0, 23), Symbol::new(0x3fffe5, 22), Symbol::new(0x3fffe6, 22), Symbol::new(0x7ffff1, 23), Symbol::new(0x3ffffe0, 26), Symbol::new(0x3ffffe1, 26), Symbol::new(0xfffeb, 20), Symbol::new(0x7fff1, 19), Symbol::new(0x3fffe7, 22), Symbol::new(0x7ffff2, 23), Symbol::new(0x3fffe8, 22), Symbol::new(0x1ffffec, 25), Symbol::new(0x3ffffe2, 26), Symbol::new(0x3ffffe3, 26), Symbol::new(0x3ffffe4, 26), Symbol::new(0x7ffffde, 27), Symbol::new(0x7ffffdf, 27), Symbol::new(0x3ffffe5, 26), Symbol::new(0xfffff1, 24), Symbol::new(0x1ffffed, 25), Symbol::new(0x7fff2, 19), Symbol::new(0x1fffe3, 21), Symbol::new(0x3ffffe6, 26), Symbol::new(0x7ffffe0, 27), Symbol::new(0x7ffffe1, 27), Symbol::new(0x3ffffe7, 26), Symbol::new(0x7ffffe2, 27), Symbol::new(0xfffff2, 24), Symbol::new(0x1fffe4, 21), Symbol::new(0x1fffe5, 21), Symbol::new(0x3ffffe8, 26), Symbol::new(0x3ffffe9, 26), Symbol::new(0xffffffd, 28), Symbol::new(0x7ffffe3, 27), Symbol::new(0x7ffffe4, 27), Symbol::new(0x7ffffe5, 27), Symbol::new(0xfffec, 20), Symbol::new(0xfffff3, 24), Symbol::new(0xfffed, 20), Symbol::new(0x1fffe6, 21), Symbol::new(0x3fffe9, 22), Symbol::new(0x1fffe7, 21), Symbol::new(0x1fffe8, 21), Symbol::new(0x7ffff3, 23), Symbol::new(0x3fffea, 22), Symbol::new(0x3fffeb, 22), Symbol::new(0x1ffffee, 25), Symbol::new(0x1ffffef, 25), Symbol::new(0xfffff4, 24), Symbol::new(0xfffff5, 24), Symbol::new(0x3ffffea, 26), Symbol::new(0x7ffff4, 23), Symbol::new(0x3ffffeb, 26), Symbol::new(0x7ffffe6, 27), Symbol::new(0x3ffffec, 26), Symbol::new(0x3ffffed, 26), Symbol::new(0x7ffffe7, 27), Symbol::new(0x7ffffe8, 27), Symbol::new(0x7ffffe9, 27), Symbol::new(0x7ffffea, 27), Symbol::new(0x7ffffeb, 27), Symbol::new(0xffffffe, 28), Symbol::new(0x7ffffec, 27), Symbol::new(0x7ffffed, 27), Symbol::new(0x7ffffee, 27), Symbol::new(0x7ffffef, 27), Symbol::new(0x7fffff0, 27), Symbol::new(0x3ffffee, 26), Symbol::new(0x3fffffff, 30), ];
pub fn table() -> &'static [Symbol; 257] {
&TABLE
}
pub static LENGTHS: [u8; 257] = {
let mut lengths = [0u8; 257];
let mut value = 0;
while value < 257 {
lengths[value] = TABLE[value].length;
value += 1;
}
lengths
};
pub struct Canonical {
pub fast: [u16; Canonical::FAST_SIZE],
pub limit: [u64; Canonical::MAX_BITS + 1],
pub base: [u32; Canonical::MAX_BITS + 1],
pub offset: [u16; Canonical::MAX_BITS + 1],
pub symbols: [u16; 257],
pub pairs: [u32; Canonical::PAIR_SIZE],
}
impl Canonical {
pub const FAST_BITS: usize = 8;
pub const FAST_SIZE: usize = 1 << Self::FAST_BITS;
pub const MAX_BITS: usize = 30;
pub const PAIR_BITS: usize = 12;
pub const PAIR_SIZE: usize = 1 << Self::PAIR_BITS;
pub const PAIR_MOST: usize = Self::PAIR_BITS / 5;
pub const fn new(table: &[Symbol; 257]) -> Self {
let mut count = [0u16; Self::MAX_BITS + 1];
let mut value = 0;
while value < 257 {
count[table[value].length as usize] += 1;
value += 1;
}
let mut base = [0u32; Self::MAX_BITS + 1];
let mut offset = [0u16; Self::MAX_BITS + 1];
let mut limit = [0u64; Self::MAX_BITS + 1];
let mut code = 0u32;
let mut index = 0u16;
let mut length = 1;
while length <= Self::MAX_BITS {
code <<= 1;
base[length] = code;
offset[length] = index;
limit[length] = match count[length] {
0 => limit[length - 1],
held => (((code + held as u32 - 1) as u64) << (64 - length)) | (u64::MAX >> length),
};
code += count[length] as u32;
index += count[length];
length += 1;
}
let mut symbols = [0u16; 257];
let mut filled = [0u16; Self::MAX_BITS + 1];
let mut value = 0;
while value < 257 {
let length = table[value].length as usize;
symbols[(offset[length] + filled[length]) as usize] = value as u16;
filled[length] += 1;
value += 1;
}
let mut fast = [0u16; Self::FAST_SIZE];
let mut value = 0;
while value < 257 {
let length = table[value].length as usize;
if length <= Self::FAST_BITS {
let first = (table[value].code as usize) << (Self::FAST_BITS - length);
let spread = 1 << (Self::FAST_BITS - length);
let mut slot = 0;
while slot < spread {
fast[first + slot] = ((value as u16) << 8) | length as u16;
slot += 1;
}
}
value += 1;
}
let mut pairs = [0u32; Self::PAIR_SIZE];
let mut index = 0;
while index < Self::PAIR_SIZE {
let mut window = (index as u64) << (64 - Self::PAIR_BITS);
let mut used = 0usize;
let mut count = 0u32;
let mut held = [0u32; 2];
while (count as usize) < Self::PAIR_MOST {
let entry = fast[(window >> (64 - Self::FAST_BITS)) as usize];
let mut length = match entry & 0xff {
0 => Self::FAST_BITS + 1,
short => short as usize,
};
while length < Self::MAX_BITS && window > limit[length] {
length += 1;
}
if used + length > Self::PAIR_BITS {
break;
}
let code = (window >> (64 - length)) as u32;
held[count as usize] = symbols[offset[length] as usize + (code - base[length]) as usize] as u32;
count += 1;
used += length;
window <<= length;
}
if count > 0 {
pairs[index] = used as u32 | count << 8 | held[0] << 16 | held[1] << 24;
}
index += 1;
}
Self { fast, limit, base, offset, symbols, pairs }
}
#[inline]
pub fn long(&self, window: u64) -> (u16, u32) {
let mut length = Self::FAST_BITS + 1;
while length < Self::MAX_BITS && window > self.limit[length] {
length += 1;
}
let code = (window >> (64 - length)) as u32;
let index = self.offset[length] as usize + (code - self.base[length]) as usize;
(self.symbols[index], length as u32)
}
#[inline]
pub fn symbol(&self, window: u64) -> (u16, u32) {
let entry = self.fast[(window >> (64 - Self::FAST_BITS)) as usize];
match entry & 0xff {
0 => self.long(window),
length => (entry >> 8, length as u32),
}
}
}
pub static CANONICAL: Canonical = Canonical::new(&TABLE);
pub struct Bits<'a> {
pub input: &'a [u8],
pub window: u64,
pub held: u32,
}
impl<'a> Bits<'a> {
pub const WIDTH: u32 = u64::BITS;
pub fn new(input: &'a [u8]) -> Self {
Self { input, window: 0, held: 0 }
}
#[inline]
pub fn mask(&self) -> u64 {
!u64::MAX.checked_shr(self.held).unwrap_or(0)
}
#[inline]
pub fn fill(&mut self) {
self.window &= self.mask();
if self.input.len() >= size_of::<u64>() && self.held <= Self::WIDTH - 8 {
let octets: [u8; 8] = self.input[..8].try_into().expect("eight octets are eight octets");
let taken = ((Self::WIDTH - self.held) / 8) as usize;
self.window |= u64::from_be_bytes(octets) >> self.held;
self.held += (taken * 8) as u32;
self.input = &self.input[taken..];
return;
}
while self.held <= Self::WIDTH - 8 {
let Some((octet, rest)) = self.input.split_first() else { return };
self.window |= (*octet as u64) << (Self::WIDTH - 8 - self.held);
self.held += 8;
self.input = rest;
}
}
#[inline]
pub fn take(&mut self, length: u32) {
debug_assert!(length <= self.held, "the window holds fewer bits than were taken");
self.window <<= length;
self.held -= length;
}
#[inline]
pub fn padded(&self) -> u64 {
self.window | u64::MAX.checked_shr(self.held).unwrap_or(0)
}
#[inline]
pub fn is_padding(&self) -> bool {
let mask = self.mask();
self.held < 8 && self.window & mask == mask
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Branch {
Node(usize),
Symbol(u16),
}
pub const NIBBLE: usize = 16;
pub const EMIT: u8 = 1 << 0;
pub const FAIL: u8 = 1 << 1;
pub const ENDED: u8 = 1 << 2;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Transition {
pub next: u16,
pub symbol: u8,
pub flags: u8,
}
impl Transition {
pub const STUCK: Self = Self { next: 0, symbol: 0, flags: FAIL };
}
pub struct DecodeTable {
pub branches: Vec<[Option<Branch>; 2]>,
pub rows: Vec<[Transition; NIBBLE]>,
pub accepting: Vec<bool>,
}
impl DecodeTable {
pub fn new(table: &[Symbol; 257]) -> Self {
let mut branches = vec![[None, None]];
for (value, symbol) in table.iter().enumerate() {
let mut node = 0;
for depth in (0..symbol.length).rev() {
let bit = (symbol.code >> depth & 1) as usize;
if depth == 0 {
branches[node][bit] = Some(Branch::Symbol(value as u16));
} else {
node = match branches[node][bit] {
Some(Branch::Node(next)) => next,
_ => {
branches.push([None, None]);
let next = branches.len() - 1;
branches[node][bit] = Some(Branch::Node(next));
next
}
};
}
}
}
let (rows, accepting) = Self::compile(&branches);
Self { branches, rows, accepting }
}
pub fn compile(branches: &[[Option<Branch>; 2]]) -> (Vec<[Transition; NIBBLE]>, Vec<bool>) {
let mut state_of = vec![u16::MAX; branches.len()];
let mut nodes = vec![0usize];
state_of[0] = 0;
let mut rows: Vec<[Transition; NIBBLE]> = Vec::new();
let mut state = 0;
while state < nodes.len() {
let mut row = [Transition::STUCK; NIBBLE];
for (nibble, slot) in row.iter_mut().enumerate() {
let mut node = nodes[state];
let mut symbol = 0u8;
let mut flags = 0u8;
for shift in (0..4).rev() {
match branches[node][nibble >> shift & 1] {
Some(Branch::Node(next)) => node = next,
Some(Branch::Symbol(EOS)) => {
flags |= ENDED;
break;
}
Some(Branch::Symbol(value)) => {
symbol = value as u8;
flags |= EMIT;
node = 0;
}
None => {
flags |= FAIL;
break;
}
}
}
if flags & (FAIL | ENDED) != 0 {
*slot = Transition { next: 0, symbol, flags };
continue;
}
if state_of[node] == u16::MAX {
state_of[node] = nodes.len() as u16;
nodes.push(node);
}
*slot = Transition { next: state_of[node], symbol, flags };
}
rows.push(row);
state += 1;
}
let mut on_ones = vec![false; branches.len()];
let mut node = 0usize;
on_ones[0] = true;
for _ in 0..7 {
match branches[node][1] {
Some(Branch::Node(next)) => {
node = next;
on_ones[node] = true;
}
_ => break,
}
}
let accepting = nodes.iter().map(|node| on_ones[*node]).collect();
(rows, accepting)
}
pub fn step(&self, node: usize, bit: bool) -> Option<Branch> {
self.branches.get(node).and_then(|pair| pair[bit as usize])
}
}
pub fn decode_table() -> &'static DecodeTable {
static DECODE_TABLE: OnceLock<DecodeTable> = OnceLock::new();
DECODE_TABLE.get_or_init(|| DecodeTable::new(table()))
}
#[derive(Debug, PartialEq, Eq)]
pub enum DecodeError {
InvalidPadding,
UnknownSymbol,
}
impl fmt::Display for DecodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidPadding => write!(f, "huffman padding is not all one-bits"),
Self::UnknownSymbol => write!(f, "huffman code does not map to a known symbol"),
}
}
}
impl std::error::Error for DecodeError {}
pub fn encode(input: &[u8]) -> Bytes {
let encoded = encoded_len(input);
let mut out = Vec::with_capacity(encoded);
encode_sized(input, encoded, &mut out);
Bytes::from(out)
}
pub fn encode_into(input: &[u8], out: &mut Vec<u8>) {
encode_sized(input, encoded_len(input), out)
}
pub fn encode_sized(input: &[u8], encoded: usize, out: &mut Vec<u8>) {
let table = table();
out.reserve(encoded);
let mut pending: u64 = 0;
let mut bits: u32 = 0;
for byte in input {
let symbol = table[*byte as usize];
pending = pending << symbol.length | symbol.code as u64;
bits += symbol.length as u32;
if bits >= 32 {
bits -= 32;
out.extend_from_slice(&((pending >> bits) as u32).to_be_bytes());
}
}
while bits >= 8 {
bits -= 8;
out.push((pending >> bits) as u8);
}
if bits > 0 {
let padding = 8 - bits;
out.push(((pending << padding) | ((1 << padding) - 1)) as u8);
}
}
pub fn decode(input: &[u8]) -> Result<Bytes, DecodeError> {
let mut out = Vec::new();
decode_into(input, &mut out)?;
Ok(Bytes::from(out))
}
pub fn decode_into(input: &[u8], out: &mut Vec<u8>) -> Result<(), DecodeError> {
decode_into_ascii(input, out).map(|_| ())
}
pub fn decode_into_ascii(input: &[u8], out: &mut Vec<u8>) -> Result<bool, DecodeError> {
let codes = &CANONICAL;
let mut bits = Bits::new(input);
out.reserve(input.len() * 8 / 5 + Canonical::PAIR_MOST);
let start = out.len();
let capacity = out.capacity();
let room = out.as_mut_ptr();
let mut written = 0usize;
let mut seen = 0u8;
loop {
bits.fill();
while bits.held >= Canonical::MAX_BITS as u32 {
let entry = codes.pairs[(bits.window >> (64 - Canonical::PAIR_BITS)) as usize];
let length = entry as u8 as u32;
if length == 0 {
let (symbol, length) = codes.long(bits.window);
if symbol == EOS {
unsafe { out.set_len(start + written) };
return Err(DecodeError::InvalidPadding);
}
debug_assert!(start + written < capacity, "a decoded symbol would land past the room reserved for it");
unsafe { room.add(start + written).write(symbol as u8) };
written += 1;
seen |= symbol as u8;
bits.take(length);
continue;
}
debug_assert!(start + written + Canonical::PAIR_MOST <= capacity, "a decoded pair would land past the room reserved for it");
unsafe { room.add(start + written).cast::<[u8; 2]>().write_unaligned(((entry >> 16) as u16).to_le_bytes()) };
written += (entry >> 8) as u8 as usize;
seen |= (entry >> 16) as u8 | (entry >> 24) as u8;
bits.take(length);
}
if bits.input.is_empty() {
break;
}
}
while !bits.is_padding() {
let (symbol, length) = codes.symbol(bits.padded());
if length > bits.held {
break;
}
if symbol == EOS {
unsafe { out.set_len(start + written) };
return Err(DecodeError::InvalidPadding);
}
debug_assert!(start + written < capacity, "a decoded symbol would land past the room reserved for it");
unsafe { room.add(start + written).write(symbol as u8) };
written += 1;
seen |= symbol as u8;
bits.take(length);
}
unsafe { out.set_len(start + written) };
match bits.is_padding() {
true => Ok(seen & 0x80 == 0),
false => Err(DecodeError::InvalidPadding),
}
}
pub fn encoded_len(input: &[u8]) -> usize {
let bits: usize = input.iter().map(|byte| LENGTHS[*byte as usize] as usize).sum();
bits.div_ceil(8)
}