retex_engine/
primitives.rs1use std::collections::HashMap;
4use std::sync::OnceLock;
5
6use crate::cmd::Cmd;
7use crate::primitives_gen::{Group, PRIMITIVES, Primitive};
8
9struct Tables {
10 by_name: HashMap<&'static [u8], &'static Primitive>,
11 by_code: HashMap<(Cmd, u32), &'static str>,
12}
13
14fn tables() -> &'static Tables {
15 static T: OnceLock<Tables> = OnceLock::new();
16 T.get_or_init(|| {
17 let mut by_name = HashMap::with_capacity(PRIMITIVES.len());
18 let mut by_code = HashMap::with_capacity(PRIMITIVES.len());
19 for p in PRIMITIVES {
20 by_name.insert(p.name.as_bytes(), p);
21 if p.cmd == Cmd::UndefinedCs {
22 continue;
23 }
24 by_code
28 .entry((p.cmd, p.chr))
29 .and_modify(|n: &mut &'static str| {
30 if p.name.len() > n.len() {
31 *n = p.name;
32 }
33 })
34 .or_insert(p.name);
35 }
36 Tables { by_name, by_code }
37 })
38}
39
40pub fn lookup(name: &[u8]) -> Option<&'static Primitive> {
42 tables().by_name.get(name).copied()
43}
44
45pub fn name_of(cmd: Cmd, chr: u32) -> Option<&'static str> {
47 tables().by_code.get(&(cmd, chr)).copied()
48}
49
50pub fn group(g: Group) -> impl Iterator<Item = &'static Primitive> {
52 PRIMITIVES.iter().filter(move |p| p.group == g)
53}
54
55#[cfg(test)]
56mod tests {
57 use super::*;
58
59 #[test]
60 fn lookups() {
61 let p = lookup(b"relax").unwrap();
62 assert_eq!(p.cmd, Cmd::Relax);
63 assert_eq!(
64 name_of(Cmd::Discretionary, 1),
65 Some("explicitdiscretionary")
66 );
67 assert_eq!(name_of(Cmd::IfTest, 12), Some("ifx"));
68 assert_eq!(group(Group::Core).count(), 1);
69 assert_eq!(group(Group::Tex).count(), 340);
70 }
71}