use std::collections::HashMap;
use std::sync::OnceLock;
use crate::cmd::Cmd;
use crate::primitives_gen::{Group, PRIMITIVES, Primitive};
struct Tables {
by_name: HashMap<&'static [u8], &'static Primitive>,
by_code: HashMap<(Cmd, u32), &'static str>,
}
fn tables() -> &'static Tables {
static T: OnceLock<Tables> = OnceLock::new();
T.get_or_init(|| {
let mut by_name = HashMap::with_capacity(PRIMITIVES.len());
let mut by_code = HashMap::with_capacity(PRIMITIVES.len());
for p in PRIMITIVES {
by_name.insert(p.name.as_bytes(), p);
if p.cmd == Cmd::UndefinedCs {
continue;
}
by_code
.entry((p.cmd, p.chr))
.and_modify(|n: &mut &'static str| {
if p.name.len() > n.len() {
*n = p.name;
}
})
.or_insert(p.name);
}
Tables { by_name, by_code }
})
}
pub fn lookup(name: &[u8]) -> Option<&'static Primitive> {
tables().by_name.get(name).copied()
}
pub fn name_of(cmd: Cmd, chr: u32) -> Option<&'static str> {
tables().by_code.get(&(cmd, chr)).copied()
}
pub fn group(g: Group) -> impl Iterator<Item = &'static Primitive> {
PRIMITIVES.iter().filter(move |p| p.group == g)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn lookups() {
let p = lookup(b"relax").unwrap();
assert_eq!(p.cmd, Cmd::Relax);
assert_eq!(
name_of(Cmd::Discretionary, 1),
Some("explicitdiscretionary")
);
assert_eq!(name_of(Cmd::IfTest, 12), Some("ifx"));
assert_eq!(group(Group::Core).count(), 1);
assert_eq!(group(Group::Tex).count(), 340);
}
}