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}
12
13pub fn is_str_interned(s: &str) -> bool {
14    STR_INTERN_CACHE.with(|interned| interned.borrow().contains(s))
15}
16
17pub fn is_arc_string_interned(s: &str) -> bool {
18    ARC_STRING_INTERN_CACHE.with(|interned| interned.borrow().contains_key(s))
19}
20
21pub fn is_snake_case_interned(s: &str) -> bool {
22    SNAKE_CASE_INTERN_CACHE.with(|interned| interned.borrow().contains_key(s))
23}
24
25#[macro_export]
26macro_rules! intern {
27    ($name:expr) => {{
28        $crate::STR_INTERN_CACHE.with(|interned| {
29            let mut interned = interned.borrow_mut();
30            if let Some(&existing) = interned.get(&*$name) {
31                existing
32            } else {
33                let name = String::from($name);
34                let static_name: &'static str = Box::leak(name.into_boxed_str());
35                interned.insert(static_name);
36                static_name
37            }
38        })
39    }};
40}
41
42#[macro_export]
43macro_rules! cache_arc_string {
44    ($name:expr) => {{
45        use std::cell::RefCell;
46        use std::collections::HashMap;
47        use std::sync::Arc;
48
49        $crate::ARC_STRING_INTERN_CACHE.with(|interned| {
50            let mut interned = interned.borrow_mut();
51            if let Some(existing) = interned.get(&*$name) {
52                Arc::clone(existing)
53            } else {
54                let name_as_string = String::from($name);
55                let static_name: &'static str = Box::leak(name_as_string.into_boxed_str());
56                let result = Arc::new(String::from(static_name));
57                interned.insert(static_name, Arc::clone(&result));
58                result
59            }
60        })
61    }};
62}
63
64#[macro_export]
65macro_rules! intern_snake_case {
66    ($name:expr) => {{
67        if $crate::is_snake_case_interned($name) {
68            $crate::SNAKE_CASE_INTERN_CACHE.with(|interned| {
69                let interned = interned.borrow();
70                *interned.get($name).unwrap()
71            })
72        } else {
73            let name = intern!($name);
74            let snake_case_name = intern!(name.to_snake_case());
75            $crate::SNAKE_CASE_INTERN_CACHE.with(|interned| {
76                let mut interned = interned.borrow_mut();
77                if let Some(existing) = interned.get(&*name) {
78                    existing
79                } else {
80                    interned.insert(name, snake_case_name);
81                    snake_case_name
82                }
83            })
84        }
85    }};
86}