Skip to main content

radiate_utils/
intern.rs

1use std::{
2    cell::RefCell,
3    collections::{HashMap, HashSet},
4    sync::Arc,
5};
6
7thread_local! {
8    pub static STR_INTERN_CACHE: RefCell<HashSet<&'static str>> = RefCell::new(HashSet::new());
9    pub static ARC_STRING_INTERN_CACHE: RefCell<HashMap<&'static str, Arc<String>>> = RefCell::new(HashMap::new());
10    pub static SNAKE_CASE_INTERN_CACHE: RefCell<HashMap<&'static str, &'static str>> = RefCell::new(HashMap::new());
11    pub static STR_CACHE: RefCell<HashMap<&'static str, &'static str>> = RefCell::new(HashMap::new());
12
13}
14
15pub fn is_str_interned(s: &str) -> bool {
16    STR_INTERN_CACHE.with(|interned| interned.borrow().contains(s))
17}
18
19pub fn is_arc_string_interned(s: &str) -> bool {
20    ARC_STRING_INTERN_CACHE.with(|interned| interned.borrow().contains_key(s))
21}
22
23pub fn is_snake_case_interned(s: &str) -> bool {
24    SNAKE_CASE_INTERN_CACHE.with(|interned| interned.borrow().contains_key(s))
25}
26
27pub fn is_str_cached(s: &str) -> bool {
28    STR_CACHE.with(|cache| cache.borrow().contains_key(s))
29}
30
31pub fn try_get_interned_str(s: &str) -> Option<&'static str> {
32    STR_CACHE.with(|interned| interned.borrow().get(s).cloned())
33}
34
35#[macro_export]
36macro_rules! intern {
37    ($name:expr) => {{
38        $crate::STR_INTERN_CACHE.with(|interned| {
39            let mut interned = interned.borrow_mut();
40            if let Some(&existing) = interned.get(&*$name) {
41                existing
42            } else {
43                let name = String::from($name);
44                let static_name: &'static str = Box::leak(name.into_boxed_str());
45                interned.insert(static_name);
46                static_name
47            }
48        })
49    }};
50}
51
52#[macro_export]
53macro_rules! cache_arc_string {
54    ($name:expr) => {{
55        use std::cell::RefCell;
56        use std::collections::HashMap;
57        use std::sync::Arc;
58
59        $crate::ARC_STRING_INTERN_CACHE.with(|interned| {
60            let mut interned = interned.borrow_mut();
61            if let Some(existing) = interned.get(&*$name) {
62                Arc::clone(existing)
63            } else {
64                let name_as_string = String::from($name);
65                let static_name: &'static str = Box::leak(name_as_string.into_boxed_str());
66                let result = Arc::new(String::from(static_name));
67                interned.insert(static_name, Arc::clone(&result));
68                result
69            }
70        })
71    }};
72}
73
74#[macro_export]
75macro_rules! intern_snake_case {
76    ($name:expr) => {{
77        if $crate::is_snake_case_interned($name) {
78            $crate::SNAKE_CASE_INTERN_CACHE.with(|interned| {
79                let interned = interned.borrow();
80                *interned.get($name).unwrap()
81            })
82        } else {
83            let name = intern!($name);
84            let snake_case_name = intern!(name.to_snake_case());
85            $crate::SNAKE_CASE_INTERN_CACHE.with(|interned| {
86                let mut interned = interned.borrow_mut();
87                if let Some(existing) = interned.get(&*name) {
88                    existing
89                } else {
90                    interned.insert(name, snake_case_name);
91                    snake_case_name
92                }
93            })
94        }
95    }};
96}
97
98#[macro_export]
99macro_rules! intern_str_cache {
100    ($name:expr, $value:expr) => {{
101        if $crate::is_str_cached($name) {
102            $crate::STR_CACHE.with(|cache| {
103                let cache = cache.borrow();
104                *cache.get($name).unwrap()
105            })
106        } else {
107            let intered_name = intern!($name);
108            let intered_value = intern!($value);
109            $crate::STR_CACHE.with(|cache| {
110                let mut cache = cache.borrow_mut();
111                if let Some(existing) = cache.get(&*intered_name) {
112                    existing
113                } else {
114                    cache.insert(intered_name, intered_value);
115                    intered_value
116                }
117            })
118        }
119    }};
120}