use std::cell::RefCell;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CoefBin {
pub site: u16,
pub bit: u8,
pub prob: u8,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Site {
pub node: u8,
pub band: u8,
pub ctx: u8,
pub tx: u8,
}
impl CoefBin {
pub fn site(&self) -> Site {
Site {
node: (self.site & 0x7) as u8,
band: ((self.site >> 3) & 0x7) as u8,
ctx: ((self.site >> 6) & 0x7) as u8,
tx: ((self.site >> 9) & 0x3) as u8,
}
}
}
struct TapState {
enabled: bool,
site: u16,
buf: Vec<CoefBin>,
}
thread_local! {
static TAP: RefCell<TapState> = const {
RefCell::new(TapState {
enabled: false,
site: 0,
buf: Vec::new(),
})
};
}
pub fn enable(on: bool) {
TAP.with(|t| {
let mut t = t.borrow_mut();
t.enabled = on;
if !on {
t.buf = Vec::new();
}
});
}
pub fn take() -> Vec<CoefBin> {
TAP.with(|t| std::mem::take(&mut t.borrow_mut().buf))
}
#[inline]
pub(crate) fn set_site(node: u8, band: u8, ctx: u8, tx: u8) {
let packed = (node as u16 & 0x7)
| ((band as u16 & 0x7) << 3)
| ((ctx as u16 & 0x7) << 6)
| ((tx as u16 & 0x3) << 9);
TAP.with(|t| t.borrow_mut().site = packed);
}
#[inline]
pub(crate) fn record(bit: u8, prob: u8) {
TAP.with(|t| {
let mut t = t.borrow_mut();
if t.enabled {
let site = t.site;
t.buf.push(CoefBin { site, bit, prob });
}
});
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn site_packs_and_unpacks() {
set_site(2, 5, 3, 1);
enable(true);
record(1, 200);
let v = take();
enable(false);
assert_eq!(v.len(), 1);
let s = v[0].site();
assert_eq!((s.node, s.band, s.ctx, s.tx), (2, 5, 3, 1));
assert_eq!((v[0].bit, v[0].prob), (1, 200));
}
#[test]
fn disabled_records_nothing() {
enable(false);
record(0, 128);
assert!(take().is_empty());
}
}