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}