use super::{
integer::{BITMAP_BASE, BITMAP_CONTEXT_COUNT},
mq::MqDecoder,
};
use crate::arith::INVALID_CONTEXT;
use crate::fallible::try_convert;
use crate::{Error, Result};
pub const IAID_BASE: usize = BITMAP_BASE + BITMAP_CONTEXT_COUNT;
pub fn decode_iaid(decoder: &mut MqDecoder<'_>, code_len: u32) -> Result<u64> {
let ids = 1usize.checked_shl(code_len);
let last = ids.and_then(|ids| IAID_BASE.checked_add(ids - 1));
if last.is_none_or(|last| decoder.context(last).is_none()) {
return Err(decoder.at(INVALID_CONTEXT));
}
let mut prev = 1u64;
for _ in 0..code_len {
let context = IAID_BASE + prev as usize;
let bit = decoder.decode_bit(context)?;
prev = prev * 2 + u64::from(bit);
}
Ok(prev - ids.unwrap_or_default() as u64)
}
pub const EMPTY_SYMBOL_SET: &str = "symbol count must be nonzero";
pub const TOO_MANY_SYMBOLS: &str = "symbol count exceeds the address space";
pub const SYMBOL_ARRAY_LENGTH: &str = "symbol array length differs from the declared count";
pub const SYMBOL_OUT_OF_RANGE: &str = "symbol ID is outside the symbol set";
pub fn checked_symbol_index(id: u64, symbol_count: u64, available_symbols: usize) -> Result<usize> {
if symbol_count == 0 {
return Err(Error::invalid(EMPTY_SYMBOL_SET));
}
let count: usize = try_convert(symbol_count, Error::invalid(TOO_MANY_SYMBOLS))?;
if available_symbols != count {
return Err(Error::invalid(SYMBOL_ARRAY_LENGTH));
}
if id >= symbol_count {
return Err(Error::invalid(SYMBOL_OUT_OF_RANGE));
}
Ok(id as usize)
}
#[cfg(test)]
mod tests;