use super::codec::{Codebook, CodebookProfile};
#[derive(Debug, Clone)]
pub struct CodebookInfo {
pub profile: CodebookProfile,
pub bits: usize,
pub len: usize,
pub min_cyclic_dist: usize,
pub seed: u64,
pub first_codeword: Option<u16>,
pub last_codeword: Option<u16>,
}
#[derive(Debug, Clone)]
pub struct CodewordMatch {
pub profile: CodebookProfile,
pub word: u16,
pub id: usize,
pub codeword: Option<u16>,
pub rotation: u8,
pub dist: u8,
pub margin: u8,
pub confidence: f32,
}
pub fn codebook_info(profile: CodebookProfile) -> CodebookInfo {
let cb = Codebook::from_profile(profile);
let (first_codeword, last_codeword) = if cb.is_empty() {
(None, None)
} else {
(cb.word(0), cb.word(cb.len() - 1))
};
CodebookInfo {
profile: cb.profile(),
bits: cb.bits(),
len: cb.len(),
min_cyclic_dist: cb.min_cyclic_dist(),
seed: cb.seed(),
first_codeword,
last_codeword,
}
}
pub fn decode_word(word: u16, profile: CodebookProfile) -> CodewordMatch {
let cb = Codebook::from_profile(profile);
let m = cb.match_word(word);
CodewordMatch {
profile: cb.profile(),
word,
id: m.id,
codeword: cb.word(m.id),
rotation: m.rotation,
dist: m.dist,
margin: m.margin,
confidence: m.confidence,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn codebook_info_reports_base_profile() {
let info = codebook_info(CodebookProfile::Base);
assert_eq!(info.profile, CodebookProfile::Base);
assert_eq!(info.bits, 16);
assert!(info.len > 0);
assert!(info.first_codeword.is_some());
assert!(info.last_codeword.is_some());
}
#[test]
fn codebook_info_matches_codebook_methods() {
for profile in [CodebookProfile::Base, CodebookProfile::Extended] {
let info = codebook_info(profile);
let cb = Codebook::from_profile(profile);
assert_eq!(info.bits, cb.bits());
assert_eq!(info.len, cb.len());
assert_eq!(info.min_cyclic_dist, cb.min_cyclic_dist());
assert_eq!(info.seed, cb.seed());
assert_eq!(info.first_codeword, cb.word(0));
assert_eq!(info.last_codeword, cb.word(cb.len() - 1));
}
}
#[test]
fn decode_word_exact_match_is_zero_distance() {
let info = codebook_info(CodebookProfile::Base);
let first = info.first_codeword.expect("non-empty codebook");
let m = decode_word(first, CodebookProfile::Base);
assert_eq!(m.id, 0);
assert_eq!(m.dist, 0);
assert_eq!(m.rotation, 0);
assert_eq!(m.codeword, Some(first));
assert_eq!(m.word, first);
assert_eq!(m.profile, CodebookProfile::Base);
}
}