1use intuicio_derive::IntuicioStruct;
2use lazy_static::lazy_static;
3use std::{
4 ops::Deref,
5 str::FromStr,
6 sync::{Arc, RwLock},
7};
8use string_interner::{
9 StringInterner,
10 backend::{Backend, BufferBackend},
11};
12
13lazy_static! {
14 static ref INTERNER: RwLock<StringInterner<BufferBackend>> =
15 RwLock::new(StringInterner::<BufferBackend>::new());
16}
17
18#[derive(IntuicioStruct, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
19pub struct Name {
20 #[intuicio(ignore)]
21 symbol: <BufferBackend as Backend>::Symbol,
22}
23
24impl Default for Name {
25 fn default() -> Self {
26 Self::new_static("")
27 }
28}
29
30impl Name {
31 pub fn new(value: impl AsRef<str>) -> Self {
32 Self {
33 symbol: INTERNER.write().unwrap().get_or_intern(value),
34 }
35 }
36
37 pub fn new_static(value: &'static str) -> Self {
38 Self {
39 symbol: INTERNER.write().unwrap().get_or_intern_static(value),
40 }
41 }
42
43 pub fn symbol(this: &Self) -> <BufferBackend as Backend>::Symbol {
44 this.symbol
45 }
46
47 pub fn read(this: &Self) -> &str {
48 INTERNER
49 .read()
50 .unwrap()
51 .resolve(this.symbol)
52 .map(|content| unsafe { std::mem::transmute(content) })
53 .unwrap_or_else(|| panic!("Could not resolve Name with symbol: {:?}", this.symbol))
54 }
55}
56
57impl Deref for Name {
58 type Target = str;
59
60 fn deref(&self) -> &Self::Target {
61 Self::read(self)
62 }
63}
64
65impl AsRef<str> for Name {
66 fn as_ref(&self) -> &str {
67 Self::read(self)
68 }
69}
70
71impl FromStr for Name {
72 type Err = ();
73
74 fn from_str(s: &str) -> Result<Self, Self::Err> {
75 Ok(Self::new(s))
76 }
77}
78
79impl From<&str> for Name {
80 fn from(value: &str) -> Self {
81 Self::new(value)
82 }
83}
84
85impl std::fmt::Debug for Name {
86 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87 write!(f, "{:?}", Self::read(self))
88 }
89}
90
91impl std::fmt::Display for Name {
92 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93 write!(f, "{}", Self::read(self))
94 }
95}
96
97#[derive(IntuicioStruct, Clone, PartialEq, PartialOrd, Hash)]
98pub struct Text {
99 #[intuicio(ignore)]
100 content: Arc<str>,
101}
102
103impl Default for Text {
104 fn default() -> Self {
105 Self {
106 content: Arc::from(""),
107 }
108 }
109}
110
111impl Text {
112 pub fn new(value: impl AsRef<str>) -> Self {
113 Self {
114 content: Arc::from(value.as_ref()),
115 }
116 }
117
118 pub fn into_inner(self) -> Arc<str> {
119 self.content
120 }
121
122 pub fn read(this: &Self) -> &str {
123 &this.content
124 }
125
126 pub fn ptr_eq(a: &Self, b: &Self) -> bool {
127 Arc::ptr_eq(&a.content, &b.content)
128 }
129}
130
131impl Deref for Text {
132 type Target = str;
133
134 fn deref(&self) -> &Self::Target {
135 Self::read(self)
136 }
137}
138
139impl AsRef<str> for Text {
140 fn as_ref(&self) -> &str {
141 Self::read(self)
142 }
143}
144
145impl FromStr for Text {
146 type Err = ();
147
148 fn from_str(s: &str) -> Result<Self, Self::Err> {
149 Ok(Self::new(s))
150 }
151}
152
153impl From<&str> for Text {
154 fn from(value: &str) -> Self {
155 Self::new(value)
156 }
157}
158
159impl std::fmt::Debug for Text {
160 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
161 write!(f, "{:?}", Self::read(self))
162 }
163}
164
165impl std::fmt::Display for Text {
166 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
167 write!(f, "{}", Self::read(self))
168 }
169}
170
171#[macro_export]
172macro_rules! name {
173 ($content:literal) => {
174 $crate::Name::new_static($content)
175 };
176}
177
178#[macro_export]
179macro_rules! text {
180 ($content:literal) => {
181 $crate::Text::new($content)
182 };
183}
184
185#[cfg(test)]
186mod tests {
187 use super::*;
188 use std::{collections::HashMap, thread::spawn};
189
190 #[test]
191 fn test_name() {
192 let a = name!("foo");
193 let b = name!("foo");
194 let c = a;
195 let d = name!("bar");
196
197 assert_eq!(a.as_ref(), "foo");
198 assert_eq!(b.as_ref(), "foo");
199 assert_eq!(c.as_ref(), "foo");
200 assert_eq!(d.as_ref(), "bar");
201 assert_eq!(a, b);
202 assert_eq!(a, c);
203 assert_eq!(b, c);
204 assert_ne!(a, d);
205 assert_ne!(b, d);
206 assert_ne!(c, d);
207 assert_eq!(Name::symbol(&a), Name::symbol(&b));
208 assert_eq!(Name::symbol(&a), Name::symbol(&c));
209 assert_eq!(Name::symbol(&b), Name::symbol(&c));
210 assert_ne!(Name::symbol(&a), Name::symbol(&d));
211 assert_ne!(Name::symbol(&b), Name::symbol(&d));
212 assert_ne!(Name::symbol(&c), Name::symbol(&d));
213 }
214
215 #[test]
216 fn test_text() {
217 let a = text!("foo");
218 let b = text!("foo");
219 let c = a.clone();
220 let d = text!("bar");
221
222 assert_eq!(a.as_ref(), "foo");
223 assert_eq!(b.as_ref(), "foo");
224 assert_eq!(c.as_ref(), "foo");
225 assert_eq!(d.as_ref(), "bar");
226 assert_eq!(a, b);
227 assert_eq!(a, c);
228 assert_eq!(b, c);
229 assert_ne!(a, d);
230 assert_ne!(b, d);
231 assert_ne!(c, d);
232 assert!(!Text::ptr_eq(&a, &b));
233 assert!(Text::ptr_eq(&a, &c));
234 assert!(!Text::ptr_eq(&b, &c));
235 assert!(!Text::ptr_eq(&a, &d));
236 assert!(!Text::ptr_eq(&b, &d));
237 assert!(!Text::ptr_eq(&c, &d));
238 }
239
240 #[test]
241 fn test_name_text_map() {
242 let mut map = HashMap::new();
243 map.insert(name!("foo"), text!("Foo"));
244 let bar = text!("Bar");
245 map.insert(name!("bar"), bar.clone());
246 map.insert(name!("bar2"), bar);
247
248 assert_eq!(map.len(), 3);
249 assert_eq!(map.get(&name!("foo")).unwrap().as_ref(), "Foo");
250 assert_eq!(map.get(&name!("bar")).unwrap().as_ref(), "Bar");
251 assert_eq!(map.get(&name!("bar2")).unwrap().as_ref(), "Bar");
252 }
253
254 #[test]
255 fn test_multi_threading() {
256 let name = name!("foo");
257 let text = text!("Foo");
258
259 assert_eq!(name.as_ref(), "foo");
260 assert_eq!(text.as_ref(), "Foo");
261
262 let (name, text) = spawn(move || {
263 assert_eq!(name.as_ref(), "foo");
264 assert_eq!(text.as_ref(), "Foo");
265 (name, text)
266 })
267 .join()
268 .unwrap();
269
270 assert_eq!(name.as_ref(), "foo");
271 assert_eq!(text.as_ref(), "Foo");
272 }
273}