1#![no_std]
2#![deny(warnings)]
3
4extern crate alloc;
5#[cfg(feature = "std")]
6extern crate std;
7
8pub mod sync;
9
10use alloc::{
11 boxed::Box,
12 collections::BTreeMap,
13 string::{String, ToString},
14 vec::Vec,
15};
16use core::{fmt, mem, ops::Deref, str};
17
18use miden_formatting::prettier::PrettyPrint;
19
20pub mod symbols {
21 include!(env!("SYMBOLS_RS"));
22}
23
24static SYMBOL_TABLE: sync::LazyLock<SymbolTable> = sync::LazyLock::new(SymbolTable::default);
25
26#[derive(Default)]
27struct SymbolTable {
28 interner: sync::RwLock<Interner>,
29}
30
31#[derive(Clone, Copy, PartialEq, Eq, Hash)]
33#[repr(transparent)]
34pub struct Symbol(SymbolIndex);
35
36#[cfg(feature = "serde")]
37impl serde::Serialize for Symbol {
38 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
39 where
40 S: serde::Serializer,
41 {
42 self.as_str().serialize(serializer)
43 }
44}
45
46#[cfg(feature = "serde")]
47impl<'de> serde::Deserialize<'de> for Symbol {
48 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
49 where
50 D: serde::Deserializer<'de>,
51 {
52 struct SymbolVisitor;
53 impl serde::de::Visitor<'_> for SymbolVisitor {
54 type Value = Symbol;
55
56 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
57 formatter.write_str("symbol")
58 }
59
60 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
61 where
62 E: serde::de::Error,
63 {
64 Ok(Symbol::intern(v))
65 }
66 }
67 deserializer.deserialize_str(SymbolVisitor)
68 }
69}
70
71impl Symbol {
72 #[inline]
73 pub const fn new(n: u32) -> Self {
74 Self(SymbolIndex::new(n))
75 }
76
77 pub fn intern(string: impl ToString) -> Self {
79 let string = string.to_string();
80 with_interner(|interner| interner.intern(string))
81 }
82
83 pub fn as_str(self) -> &'static str {
84 with_read_only_interner(|interner| unsafe {
85 mem::transmute::<&str, &'static str>(interner.get(self))
88 })
89 }
90
91 #[inline]
92 pub const fn as_u32(self) -> u32 {
93 self.0.as_u32()
94 }
95
96 #[inline]
97 pub const fn as_usize(self) -> usize {
98 self.0.as_usize()
99 }
100
101 #[inline]
103 pub fn is_keyword(self) -> bool {
104 symbols::is_keyword(self)
105 }
106}
107impl fmt::Debug for Symbol {
108 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
109 write!(f, "{}({:?})", self, self.0)
110 }
111}
112impl fmt::Display for Symbol {
113 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
114 fmt::Display::fmt(&self.as_str(), f)
115 }
116}
117impl PrettyPrint for Symbol {
118 fn render(&self) -> miden_formatting::prettier::Document {
119 use miden_formatting::prettier::*;
120 const_text(self.as_str())
121 }
122}
123impl PartialOrd for Symbol {
124 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
125 Some(self.cmp(other))
126 }
127}
128impl Ord for Symbol {
129 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
130 self.as_str().cmp(other.as_str())
131 }
132}
133impl AsRef<str> for Symbol {
134 #[inline(always)]
135 fn as_ref(&self) -> &str {
136 self.as_str()
137 }
138}
139impl core::borrow::Borrow<str> for Symbol {
140 #[inline(always)]
141 fn borrow(&self) -> &str {
142 self.as_str()
143 }
144}
145impl<T: Deref<Target = str>> PartialEq<T> for Symbol {
146 fn eq(&self, other: &T) -> bool {
147 self.as_str() == other.deref()
148 }
149}
150impl From<&'static str> for Symbol {
151 fn from(s: &'static str) -> Self {
152 with_interner(|interner| interner.insert(s))
153 }
154}
155impl From<String> for Symbol {
156 fn from(s: String) -> Self {
157 Self::intern(s)
158 }
159}
160impl From<Box<str>> for Symbol {
161 fn from(s: Box<str>) -> Self {
162 Self::intern(s)
163 }
164}
165impl From<alloc::borrow::Cow<'static, str>> for Symbol {
166 fn from(s: alloc::borrow::Cow<'static, str>) -> Self {
167 use alloc::borrow::Cow;
168 match s {
169 Cow::Borrowed(s) => s.into(),
170 Cow::Owned(s) => Self::intern(s),
171 }
172 }
173}
174#[cfg(feature = "compact_str")]
175impl From<compact_str::CompactString> for Symbol {
176 fn from(s: compact_str::CompactString) -> Self {
177 Self::intern(s.into_string())
178 }
179}
180
181#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
182#[repr(transparent)]
183struct SymbolIndex(u32);
184impl SymbolIndex {
185 pub const MAX_AS_U32: u32 = 0xffff_ff00;
187
188 #[inline]
189 const fn new(n: u32) -> Self {
190 assert!(n <= Self::MAX_AS_U32, "out of range value used");
191
192 SymbolIndex(n)
193 }
194
195 #[inline]
196 pub const fn as_u32(self) -> u32 {
197 self.0
198 }
199
200 #[inline]
201 pub const fn as_usize(self) -> usize {
202 self.0 as usize
203 }
204}
205impl From<SymbolIndex> for u32 {
206 #[inline]
207 fn from(v: SymbolIndex) -> u32 {
208 v.as_u32()
209 }
210}
211impl From<SymbolIndex> for usize {
212 #[inline]
213 fn from(v: SymbolIndex) -> usize {
214 v.as_usize()
215 }
216}
217
218struct Interner {
219 pub names: BTreeMap<&'static str, Symbol>,
220 pub strings: Vec<&'static str>,
221}
222
223impl Default for Interner {
224 fn default() -> Self {
225 let mut this = Self {
226 names: BTreeMap::default(),
227 strings: Vec::with_capacity(symbols::__SYMBOLS.len()),
228 };
229 for (sym, s) in symbols::__SYMBOLS {
230 this.names.insert(s, *sym);
231 this.strings.push(s);
232 }
233 this
234 }
235}
236
237impl Interner {
238 pub fn intern(&mut self, string: String) -> Symbol {
239 if let Some(&name) = self.names.get(string.as_str()) {
240 return name;
241 }
242
243 let name = Symbol::new(self.strings.len() as u32);
244
245 let string = string.into_boxed_str();
246 let string: &'static str = Box::leak(string);
247 self.strings.push(string);
248 self.names.insert(string, name);
249 name
250 }
251
252 pub fn insert(&mut self, s: &'static str) -> Symbol {
253 if let Some(&name) = self.names.get(s) {
254 return name;
255 }
256 let name = Symbol::new(self.strings.len() as u32);
257 self.strings.push(s);
258 self.names.insert(s, name);
259 name
260 }
261
262 pub fn get(&self, symbol: Symbol) -> &'static str {
263 self.strings[symbol.0.as_usize()]
264 }
265}
266
267#[inline]
269fn with_interner<T, F: FnOnce(&mut Interner) -> T>(f: F) -> T {
270 let mut table = SYMBOL_TABLE.interner.write();
271 f(&mut table)
272}
273
274#[inline]
275fn with_read_only_interner<T, F: FnOnce(&Interner) -> T>(f: F) -> T {
276 let table = SYMBOL_TABLE.interner.read();
277 f(&table)
278}