Skip to main content

draco_oxide_core/codec/entropy/
mod.rs

1use crate::bit_coder::{ByteReader, ByteWriter, ReaderErr};
2
3pub mod rans;
4
5pub const L_RANS_BASE: usize = 4096;
6pub const DEFAULT_RANS_PRECISION: usize = 12;
7pub const DEFAULT_RABS_PRECISION: usize = 8;
8
9#[derive(Debug, Clone, PartialEq, Eq)]
10pub enum SymbolEncodingMethod {
11    #[allow(unused)]
12    LengthCoded,
13    DirectCoded,
14}
15
16impl SymbolEncodingMethod {
17    #[allow(unused)]
18    pub fn read_from<R>(reader: &mut R) -> Result<Self, Err>
19    where
20        R: ByteReader,
21    {
22        let method = reader.read_u8()?;
23        match method {
24            0 => Ok(SymbolEncodingMethod::LengthCoded),
25            1 => Ok(SymbolEncodingMethod::DirectCoded),
26            _ => Err(Err::InvalidSymbolEncodingMethod),
27        }
28    }
29    pub fn write_to<W>(&self, writer: &mut W)
30    where
31        W: ByteWriter,
32    {
33        match self {
34            SymbolEncodingMethod::LengthCoded => writer.write_u8(0),
35            SymbolEncodingMethod::DirectCoded => writer.write_u8(1),
36        }
37    }
38}
39
40pub struct RansSymbol {
41    pub freq_count: usize,
42    pub freq_cumulative: usize,
43}
44
45pub fn rans_build_tables<const RANS_PRECISION: usize>(
46    freq_counts: &[usize],
47) -> Result<(Vec<usize>, Vec<RansSymbol>), Err> {
48    let mut slot_table = Vec::with_capacity(1 << RANS_PRECISION);
49    let mut rans_syms = Vec::with_capacity(freq_counts.len());
50
51    let mut freq_cumulative = 0;
52    for (i, freq_count) in freq_counts.iter().enumerate() {
53        let symbol = RansSymbol {
54            freq_count: *freq_count,
55            freq_cumulative,
56        };
57        rans_syms.push(symbol);
58        let tmp = freq_cumulative;
59        freq_cumulative = freq_cumulative
60            .checked_add(*freq_count)
61            .ok_or(Err::InvalidFreqCount)?; // cumulative frequency count is not inclusive, so this operation is done after creating the symbol
62        for _ in tmp..freq_cumulative {
63            slot_table.push(i);
64        }
65    }
66
67    if freq_cumulative != 1 << RANS_PRECISION {
68        return Err(Err::FrequencyCountNotCompatibleWithRansPrecision(
69            freq_cumulative,
70            1 << RANS_PRECISION,
71        ));
72    }
73
74    Ok((slot_table, rans_syms))
75}
76
77#[derive(thiserror::Error, Debug, Clone, Copy, PartialEq, Eq)]
78pub enum Err {
79    #[error(
80        "Frequency count not compatible with RANS precision: freq_count=={0}!={1}==rans_precision"
81    )]
82    FrequencyCountNotCompatibleWithRansPrecision(usize, usize),
83    #[error("Invalid frequency count")]
84    InvalidFreqCount,
85    #[error("Invalid symbol encoding method")]
86    InvalidSymbolEncodingMethod,
87    #[error("Reader error")]
88    ReaderError(#[from] ReaderErr),
89}