use std::sync::OnceLock;
use super::tables::{
self, DecompressTables, LITLEN_TABLEBITS, LITLEN_TABLE_SIZE,
DIST_TABLEBITS, DIST_TABLE_SIZE,
};
fn fixed_litlen_lens() -> [u8; 288] {
let mut lens = [0u8; 288];
for i in 0..=143 { lens[i] = 8; }
for i in 144..=255 { lens[i] = 9; }
for i in 256..=279 { lens[i] = 7; }
for i in 280..=287 { lens[i] = 8; }
lens
}
fn fixed_dist_lens() -> [u8; 32] {
[5u8; 32]
}
struct FixedTables {
litlen: [u32; LITLEN_TABLE_SIZE],
dist: [u32; DIST_TABLE_SIZE],
}
static FIXED: OnceLock<FixedTables> = OnceLock::new();
fn get_fixed() -> &'static FixedTables {
FIXED.get_or_init(|| {
let litlen_lens = fixed_litlen_lens();
let dist_lens = fixed_dist_lens();
let mut litlen = [0u32; LITLEN_TABLE_SIZE];
let mut dist = [0u32; DIST_TABLE_SIZE];
tables::build_decode_table(&litlen_lens, &mut litlen, LITLEN_TABLEBITS, tables::TableKind::Litlen)
.expect("fixed litlen table build must succeed");
tables::build_decode_table(&dist_lens, &mut dist, DIST_TABLEBITS, tables::TableKind::Dist)
.expect("fixed dist table build must succeed");
FixedTables { litlen, dist }
})
}
pub fn load_fixed_tables(tables: &mut DecompressTables) {
let fixed = get_fixed();
tables.litlen.copy_from_slice(&fixed.litlen);
tables.dist[..DIST_TABLE_SIZE].copy_from_slice(&fixed.dist);
}
#[cfg(test)]
mod tests {
use super::*;
use crate::tables::{HUFFDEC_LITERAL, HUFFDEC_END_OF_BLOCK, entry_literal};
#[test]
fn fixed_tables_build_successfully() {
let fixed = get_fixed();
let mut found_eob = false;
let mut found_lit = false;
for &entry in fixed.litlen.iter().take(1 << LITLEN_TABLEBITS) {
if entry & HUFFDEC_END_OF_BLOCK != 0 {
found_eob = true;
}
if entry & HUFFDEC_LITERAL != 0 && entry_literal(entry) == b'A' {
found_lit = true;
}
}
assert!(found_eob, "should find EOB in fixed litlen table");
assert!(found_lit, "should find 'A' literal in fixed litlen table");
}
}