intern_all/
global.rs

1use std::borrow::Borrow;
2use std::hash::Hash;
3
4use lazy_static::lazy_static;
5
6use crate::interner::Interner;
7use crate::token::Internable;
8use crate::Tok;
9
10lazy_static! {
11  static ref SINGLETON: Interner = Interner::new();
12}
13
14/// Create a thread-local token instance and copy it. This ensures that the
15/// interner will only be called the first time the expresion is executed,
16/// and subsequent calls will just copy the token. Accepts a single static
17/// expression (i.e. a literal).
18#[macro_export]
19macro_rules! i {
20  ($ty:ty : $expr:expr) => {{
21    thread_local! {
22      static VALUE: $crate::Tok<<$ty as ToOwned>::Owned> = $crate::i($expr as &$ty);
23    }
24    VALUE.with(|v| v.clone())
25  }};
26}
27
28/// Intern something with the global interner. If Q is static, you should
29/// consider using the macro version of this function.
30#[must_use]
31pub fn i<Q>(q: &Q) -> Tok<Q::Owned>
32where
33  Q: ?Sized + Eq + Hash + ToOwned,
34  Q::Owned: Borrow<Q> + Internable,
35{
36  SINGLETON.i(q)
37}
38
39/// Fully resolve a list of interned things. If the list is interned, use
40/// [Tok#ev]
41#[must_use]
42pub fn ev<'a, T: Internable>(s: impl IntoIterator<Item = &'a Tok<T>>) -> Vec<T> {
43  s.into_iter().map(|t| (**t).clone()).collect()
44}
45
46/// Sweep values of a specific type from the global interner. Useful if you just
47/// constructed a large number of values of a specific type, otherwise use
48/// [sweep]
49pub fn sweep_t<T: Internable>() -> usize { SINGLETON.sweep_t::<T>() }
50
51/// Sweep the global interner. If you want to sweep a specific type, try
52/// [sweep_t]
53pub fn sweep() -> usize { SINGLETON.sweep() }
54
55/// Intern a list and its elements in the global interner. See also [ibv]
56pub fn iv<T: Internable>(s: impl IntoIterator<Item = T>) -> Tok<Vec<Tok<T>>> { SINGLETON.iv(s) }
57
58/// Intern a list of borrowed items in the global interner. See also [iv]
59pub fn ibv<'a, Q>(s: impl IntoIterator<Item = &'a Q>) -> Tok<Vec<Tok<Q::Owned>>>
60where
61  Q: ?Sized + Eq + Hash + ToOwned + 'a,
62  Q::Owned: Internable,
63{
64  SINGLETON.ibv(s)
65}
66
67#[cfg(test)]
68mod test {
69  use std::any::{type_name, type_name_of_val};
70
71  use super::i;
72  use crate::Tok;
73
74  #[test]
75  pub fn statics() {
76    let a = i!(str: "foo");
77    let b = i!(str: "foo");
78    let c = i("foo");
79    assert_eq!(a, b);
80    assert_eq!(a, c);
81    let v = i!([Tok<String>]: &[i("foo"), i("bar"), i("baz")]);
82    assert_eq!(type_name_of_val(&v), type_name::<Tok<Vec<Tok<String>>>>());
83  }
84}