1use std::sync::{OnceLock, RwLock};
2
3use dashmap::DashMap;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
7pub struct SymbolId(pub u32);
8
9pub struct SymbolTable {
12 names: RwLock<Vec<String>>,
13 map: DashMap<String, SymbolId>,
14}
15
16impl SymbolTable {
17 pub fn new() -> SymbolTable {
18 SymbolTable {
19 names: RwLock::new(Vec::new()),
20 map: DashMap::new(),
21 }
22 }
23
24 pub fn global() -> &'static SymbolTable {
25 static TABLE: OnceLock<SymbolTable> = OnceLock::new();
26 TABLE.get_or_init(|| {
27 let t = SymbolTable::new();
28 crate::builtins::register(&t);
29 t
30 })
31 }
32
33 pub fn intern(&self, name: &str) -> SymbolId {
34 if let Some(id) = self.map.get(name) {
35 return *id;
36 }
37 let mut names = self.names.write().unwrap();
38 if let Some(id) = self.map.get(name) {
39 return *id;
40 }
41 let id = SymbolId(names.len() as u32);
42 names.push(name.to_string());
43 self.map.insert(name.to_string(), id);
44 id
45 }
46
47 pub fn intern_display(&self, name: &str, display: &str) -> SymbolId {
49 if let Some(id) = self.map.get(name) {
50 return *id;
51 }
52 let mut names = self.names.write().unwrap();
53 if let Some(id) = self.map.get(name) {
54 return *id;
55 }
56 let id = SymbolId(names.len() as u32);
57 names.push(display.to_string());
58 self.map.insert(name.to_string(), id);
59 id
60 }
61
62 pub fn name(&self, id: SymbolId) -> Option<String> {
63 self.names.read().unwrap().get(id.0 as usize).cloned()
64 }
65}
66
67impl Default for SymbolTable {
68 fn default() -> Self {
69 Self::new()
70 }
71}