1use std::collections::HashMap;
21use std::fmt;
22use yog_sync::{OnceLock, RwLock};
23
24#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
26pub struct Atom(u32);
27
28#[derive(Clone, Copy)]
31pub struct Table {
32 pub intern: fn(&str) -> u32,
33 pub name: fn(u32) -> Option<&'static str>,
34}
35
36static TABLE: OnceLock<Table> = OnceLock::new();
37
38pub fn install(table: Table) -> bool {
41 TABLE.set(table).is_ok()
42}
43
44fn table() -> &'static Table {
45 TABLE.get_or_init(|| Table {
46 intern: local::intern,
47 name: local::name,
48 })
49}
50
51impl Atom {
52 pub fn new(name: &str) -> Atom {
54 Atom((table().intern)(name))
55 }
56
57 pub fn from_number(n: u32) -> Option<Atom> {
59 (table().name)(n).map(|_| Atom(n))
60 }
61
62 pub fn number(self) -> u32 {
63 self.0
64 }
65
66 pub fn as_str(self) -> &'static str {
67 (table().name)(self.0).unwrap_or_default()
68 }
69}
70
71impl fmt::Debug for Atom {
72 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73 write!(f, "Atom({:?})", self.as_str())
74 }
75}
76
77impl fmt::Display for Atom {
78 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79 f.write_str(self.as_str())
80 }
81}
82
83impl From<&str> for Atom {
84 fn from(name: &str) -> Atom {
85 Atom::new(name)
86 }
87}
88
89impl From<String> for Atom {
90 fn from(name: String) -> Atom {
91 Atom::new(&name)
92 }
93}
94
95impl From<&String> for Atom {
96 fn from(name: &String) -> Atom {
97 Atom::new(name)
98 }
99}
100
101impl PartialEq<str> for Atom {
102 fn eq(&self, other: &str) -> bool {
103 self.as_str() == other
104 }
105}
106
107impl PartialEq<&str> for Atom {
108 fn eq(&self, other: &&str) -> bool {
109 self.as_str() == *other
110 }
111}
112
113impl std::ops::Deref for Atom {
114 type Target = str;
115 fn deref(&self) -> &str {
116 self.as_str()
117 }
118}
119
120impl Default for Atom {
121 fn default() -> Atom {
123 Atom::new("")
124 }
125}
126
127pub mod local;
129
130#[cfg(test)]
131mod tests {
132 use super::*;
133
134 #[test]
135 fn a_name_is_one_atom() {
136 let a = Atom::new("test:atom_a");
137 assert_eq!(a, Atom::new("test:atom_a"));
138 assert_ne!(a, Atom::new("test:atom_b"));
139 assert_eq!(Atom::from_number(a.number()), Some(a));
140 assert_eq!(Atom::from_number(u32::MAX), None);
141 assert_eq!(a.to_string(), "test:atom_a");
142 }
143}