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