1use crate::source_map::SourceMap;
18
19use core::{
20 borrow::Borrow,
21 cmp::PartialEq,
22 fmt,
23 hash::{Hash, Hasher},
24 num::NonZeroU32,
25 ops::Deref,
26 str,
27};
28use fxhash::FxBuildHasher;
29use indexmap::IndexSet;
30use serde::{Deserialize, Deserializer, Serialize, Serializer};
31use std::cell::RefCell;
32
33include!(concat!(env!("OUT_DIR"), "/symbols_generated.rs"));
35
36#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
41pub struct Symbol(
42 #[serde(deserialize_with = "Symbol::serde_to_symbol")]
43 #[serde(serialize_with = "Symbol::serde_from_symbol")]
44 NonZeroU32,
45);
46
47impl Default for Symbol {
48 fn default() -> Self {
49 Symbol(NonZeroU32::MIN)
50 }
51}
52
53impl Symbol {
54 pub const fn new(index: u32) -> Self {
56 let index = index.saturating_add(1);
57 Self(match NonZeroU32::new(index) {
58 None => unreachable!(),
59 Some(x) => x,
60 })
61 }
62
63 pub fn intern(string: &str) -> Self {
65 with_session_globals(|session_globals| session_globals.symbol_interner.intern(string))
66 }
67
68 pub fn as_str<R>(self, s: &SessionGlobals, with: impl FnOnce(&str) -> R) -> R {
70 s.symbol_interner.get(self, with)
71 }
72
73 pub const fn as_u32(self) -> u32 {
75 self.0.get() - 1
76 }
77
78 fn serde_to_symbol<'de, D: Deserializer<'de>>(de: D) -> Result<NonZeroU32, D::Error> {
79 Ok(Symbol::intern(<&str>::deserialize(de)?).0)
80 }
81
82 fn serde_from_symbol<S: Serializer>(index: &NonZeroU32, ser: S) -> Result<S::Ok, S::Error> {
83 with_session_globals(|sg| Self(*index).as_str(sg, |s| ser.serialize_str(s)))
84 }
85}
86
87impl fmt::Debug for Symbol {
88 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89 with_session_globals(|s| self.as_str(s, |s| fmt::Debug::fmt(s, f)))
90 }
91}
92
93impl fmt::Display for Symbol {
94 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95 with_session_globals(|s| self.as_str(s, |s| fmt::Display::fmt(s, f)))
96 }
97}
98
99pub struct SessionGlobals {
101 symbol_interner: Interner,
103 pub source_map: SourceMap,
105}
106
107impl Default for SessionGlobals {
108 fn default() -> Self {
109 Self { symbol_interner: Interner::prefilled(), source_map: SourceMap::default() }
110 }
111}
112
113scoped_tls::scoped_thread_local!(pub static SESSION_GLOBALS: SessionGlobals);
114
115#[inline]
117pub fn create_session_if_not_set_then<R>(f: impl FnOnce(&SessionGlobals) -> R) -> R {
118 if !SESSION_GLOBALS.is_set() {
119 let sg = SessionGlobals::default();
120 SESSION_GLOBALS.set(&sg, || SESSION_GLOBALS.with(f))
121 } else {
122 SESSION_GLOBALS.with(f)
123 }
124}
125
126#[inline]
128pub fn with_session_globals<R>(f: impl FnOnce(&SessionGlobals) -> R) -> R {
129 SESSION_GLOBALS.with(f)
130}
131
132#[derive(Eq)]
136enum InternedStr {
137 Static(&'static str),
139 Owned(Box<str>),
141}
142
143impl Borrow<str> for InternedStr {
144 fn borrow(&self) -> &str {
145 self.deref()
146 }
147}
148
149impl Deref for InternedStr {
150 type Target = str;
151
152 fn deref(&self) -> &Self::Target {
153 match self {
154 Self::Static(s) => s,
155 Self::Owned(s) => s,
156 }
157 }
158}
159
160impl PartialEq for InternedStr {
161 fn eq(&self, other: &InternedStr) -> bool {
162 self.deref() == other.deref()
163 }
164}
165
166impl Hash for InternedStr {
167 fn hash<H: Hasher>(&self, state: &mut H) {
168 self.deref().hash(state);
169 }
170}
171
172struct InnerInterner {
175 set: IndexSet<InternedStr, FxBuildHasher>,
179}
180
181struct Interner {
183 inner: RefCell<InnerInterner>,
184}
185
186impl Interner {
187 fn prefilled() -> Self {
189 Self::prefill(PRE_DEFINED)
190 }
191
192 fn prefill(init: &[&'static str]) -> Self {
194 let inner = InnerInterner {
195 set: init.iter().copied().map(InternedStr::Static).collect(),
197 };
198 Self { inner: RefCell::new(inner) }
199 }
200
201 fn intern(&self, string: &str) -> Symbol {
203 let InnerInterner { set } = &mut *self.inner.borrow_mut();
204
205 if let Some(sym) = set.get_index_of(string) {
206 return Symbol::new(sym as u32);
208 }
209
210 Symbol::new(set.insert_full(InternedStr::Owned(string.into())).0 as u32)
211 }
212
213 fn get<R>(&self, symbol: Symbol, with: impl FnOnce(&str) -> R) -> R {
215 let set = &self.inner.borrow().set;
216 with(set.get_index(symbol.as_u32() as usize).unwrap())
217 }
218}