1use std::collections::HashMap;
9
10#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
15pub struct Symbol(u32);
16
17impl Symbol {
18 #[inline]
20 pub fn as_u32(self) -> u32 {
21 self.0
22 }
23
24 #[inline]
26 pub fn from_raw(index: u32) -> Self {
27 Self(index)
28 }
29}
30
31impl PartialOrd for Symbol {
32 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
33 Some(self.cmp(other))
34 }
35}
36
37impl Ord for Symbol {
38 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
39 self.0.cmp(&other.0)
40 }
41}
42
43#[derive(Debug, Clone, Default)]
45pub struct Interner {
46 map: HashMap<String, Symbol>,
48 strings: Vec<String>,
50}
51
52impl Interner {
53 pub fn new() -> Self {
54 Self::default()
55 }
56
57 pub fn intern(&mut self, s: &str) -> Symbol {
60 if let Some(&sym) = self.map.get(s) {
61 return sym;
62 }
63
64 let sym = Symbol(self.strings.len() as u32);
65 self.strings.push(s.to_owned());
66 self.map.insert(s.to_owned(), sym);
67 sym
68 }
69
70 pub fn intern_owned(&mut self, s: String) -> Symbol {
72 if let Some(&sym) = self.map.get(&s) {
73 return sym;
74 }
75
76 let sym = Symbol(self.strings.len() as u32);
77 self.strings.push(s.clone());
78 self.map.insert(s, sym);
79 sym
80 }
81
82 #[inline]
87 pub fn resolve(&self, sym: Symbol) -> &str {
88 &self.strings[sym.0 as usize]
89 }
90
91 #[inline]
93 pub fn try_resolve(&self, sym: Symbol) -> Option<&str> {
94 self.strings.get(sym.0 as usize).map(|s| s.as_str())
95 }
96
97 #[inline]
99 pub fn len(&self) -> usize {
100 self.strings.len()
101 }
102
103 #[inline]
105 pub fn is_empty(&self) -> bool {
106 self.strings.is_empty()
107 }
108
109 #[inline]
111 pub fn iter(&self) -> impl Iterator<Item = (Symbol, &str)> {
112 self.strings
113 .iter()
114 .enumerate()
115 .map(|(i, s)| (Symbol(i as u32), s.as_str()))
116 }
117
118 pub fn to_blob(&self) -> (Vec<u8>, Vec<u32>) {
123 let mut blob = Vec::new();
124 let mut offsets = Vec::with_capacity(self.strings.len() + 1);
125
126 for s in &self.strings {
127 offsets.push(blob.len() as u32);
128 blob.extend_from_slice(s.as_bytes());
129 }
130 offsets.push(blob.len() as u32); (blob, offsets)
133 }
134}