1use std::{
2 cell::RefCell,
3 collections::{HashMap, HashSet},
4};
5
6thread_local! {
7 pub static STR_INTERN_CACHE: RefCell<HashSet<&'static str>> = RefCell::new(HashSet::new());
8 pub static STR_CACHE: RefCell<HashMap<&'static str, &'static str>> = RefCell::new(HashMap::new());
9
10}
11
12pub fn is_str_interned(s: &str) -> bool {
13 STR_INTERN_CACHE.with(|interned| interned.borrow().contains(s))
14}
15
16pub fn is_str_cached(s: &str) -> bool {
17 STR_CACHE.with(|cache| cache.borrow().contains_key(s))
18}
19
20pub fn try_get_interned_str(s: &str) -> Option<&'static str> {
21 STR_CACHE.with(|interned| interned.borrow().get(s).cloned())
22}
23
24#[macro_export]
25macro_rules! intern {
26 ($name:expr) => {{
27 $crate::STR_INTERN_CACHE.with(|interned| {
28 let mut interned = interned.borrow_mut();
29 if let Some(&existing) = interned.get(&*$name) {
30 existing
31 } else {
32 let name = String::from($name);
33 let static_name: &'static str = Box::leak(name.into_boxed_str());
34 interned.insert(static_name);
35 static_name
36 }
37 })
38 }};
39}
40
41#[macro_export]
42macro_rules! intern_str_cache {
43 ($name:expr, $value:expr) => {{
44 if $crate::is_str_cached($name) {
45 $crate::STR_CACHE.with(|cache| {
46 let cache = cache.borrow();
47 *cache.get($name).unwrap()
48 })
49 } else {
50 let intered_name = intern!($name);
51 let intered_value = intern!($value);
52 $crate::STR_CACHE.with(|cache| {
53 let mut cache = cache.borrow_mut();
54 if let Some(existing) = cache.get(&*intered_name) {
55 existing
56 } else {
57 cache.insert(intered_name, intered_value);
58 intered_value
59 }
60 })
61 }
62 }};
63}