statsig_rust/
interned_string.rs1use std::{
2 borrow::Cow,
3 fmt::Display,
4 hash::{Hash, Hasher},
5 ops::Deref,
6 sync::Arc,
7};
8
9use serde::{Deserialize, Deserializer, Serialize, Serializer};
10use serde_json::value::RawValue;
11
12use crate::{
13 evaluation::dynamic_string::DynamicString, hashing, impl_interned_value,
14 interned_value_store::FromRawValue, log_e,
15};
16
17lazy_static::lazy_static! {
18 static ref EMPTY: InternedString = InternedString {
19 hash: 0,
20 value: Arc::new(String::new()),
21 };
22
23 static ref TRUE_STRING: InternedString = InternedString::from_string("true".to_string());
24 static ref FALSE_STRING: InternedString = InternedString::from_string("false".to_string());
25
26 static ref DEFAULT_RULE_ID: InternedString = InternedString::from_str_ref("default");
27}
28
29const TAG: &str = "InternedString";
30
31#[derive(Clone, Debug, Eq)]
32pub struct InternedString {
33 pub hash: u64,
34 pub value: Arc<String>,
35}
36
37#[macro_export]
38macro_rules! interned_str {
39 ($value:literal) => {
41 InternedString::from_str_ref($value)
42 };
43 (bool: $value:literal) => {
45 InternedString::from_bool($value)
46 };
47 ($value:expr) => {
49 InternedString::from_string($value)
50 };
51 ($value:expr) => {
53 InternedString::from_dynamic_string($value)
54 };
55 ( $value:expr) => {
57 InternedString::from_str_parts($value)
58 };
59}
60
61impl InternedString {
62 pub fn default_rule_id_ref() -> &'static Self {
63 &DEFAULT_RULE_ID
64 }
65
66 pub fn default_rule_id() -> Self {
67 DEFAULT_RULE_ID.clone()
68 }
69
70 pub fn from_str_ref(value: &str) -> Self {
71 let hash = hashing::hash_one(value);
72 let value = InternedString::get_or_create_memoized_string(hash, Cow::Borrowed(value));
73 Self { hash, value }
74 }
75
76 pub fn from_string(value: String) -> Self {
77 let hash = hashing::hash_one(value.as_str());
78 let value = InternedString::get_or_create_memoized_string(hash, Cow::Owned(value));
79 Self { hash, value }
80 }
81
82 pub fn from_bool(value: bool) -> Self {
83 if value {
84 TRUE_STRING.clone()
85 } else {
86 FALSE_STRING.clone()
87 }
88 }
89
90 pub fn from_dynamic_string(value: &DynamicString) -> Self {
91 let hash = value.hash_value;
92 let value =
93 InternedString::get_or_create_memoized_string(hash, Cow::Borrowed(&value.value));
94 Self { hash, value }
95 }
96
97 pub fn from_str_parts(parts: &[&str]) -> Self {
98 let mut value = String::new();
99 for v in parts {
100 value.push_str(v);
101 }
102
103 Self::from_string(value)
104 }
105
106 pub fn as_str(&self) -> &str {
107 self.value.as_str()
108 }
109
110 pub fn unperformant_to_string(&self) -> String {
113 self.value.to_string()
114 }
115
116 pub fn empty_ref() -> &'static Self {
117 &EMPTY
118 }
119
120 pub fn empty() -> Self {
121 EMPTY.clone()
122 }
123
124 pub fn is_empty(&self) -> bool {
125 self.value.is_empty()
126 }
127
128 fn get_or_create_memoized_string(hash: u64, input: Cow<'_, str>) -> Arc<String> {
129 if let Some(value) = INTERNED_STORE.try_get_interned_value(hash) {
130 return value;
131 }
132
133 let value = input.to_string();
134 let value_arc = Arc::new(value);
135 INTERNED_STORE.set_interned_value(hash, &value_arc);
136 value_arc
137 }
138}
139
140impl_interned_value!(InternedString, String);
141
142impl<'de> Deserialize<'de> for InternedString {
143 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
144 where
145 D: Deserializer<'de>,
146 {
147 #[derive(Deserialize)]
148 #[serde(untagged)]
149 enum CowString<'a> {
150 #[serde(borrow)]
151 Borrowed(&'a str), Owned(String), }
154
155 let raw: CowString<'de> = CowString::deserialize(deserializer)?;
156 match raw {
157 CowString::Borrowed(raw) => {
158 let hash = hashing::hash_one(raw);
159 let value = InternedString::get_or_create_memoized_string(hash, Cow::Borrowed(raw));
160 Ok(InternedString { hash, value })
161 }
162 CowString::Owned(raw) => {
163 let hash = hashing::hash_one(raw.as_str());
164 let value = InternedString::get_or_create_memoized_string(hash, Cow::Owned(raw));
165 Ok(InternedString { hash, value })
166 }
167 }
168 }
169}
170
171impl Serialize for InternedString {
172 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
173 where
174 S: Serializer,
175 {
176 self.value.serialize(serializer)
177 }
178}
179
180impl FromRawValue for String {
181 fn from_raw_value(raw_value: Cow<'_, RawValue>) -> Self {
182 match serde_json::from_str(raw_value.get()) {
183 Ok(value) => value,
184 Err(e) => {
185 log_e!(TAG, "Failed to convert raw value to String: {}", e);
186 String::new()
187 }
188 }
189 }
190}
191
192impl PartialEq for InternedString {
193 fn eq(&self, other: &Self) -> bool {
194 self.as_str() == other.as_str()
195 }
196}
197
198impl Hash for InternedString {
199 fn hash<H: Hasher>(&self, state: &mut H) {
200 self.hash.hash(state);
201 }
202}
203
204impl PartialEq<&str> for InternedString {
205 fn eq(&self, other: &&str) -> bool {
206 self.as_str() == *other
207 }
208}
209
210impl PartialEq<str> for InternedString {
211 fn eq(&self, other: &str) -> bool {
212 self.as_str() == other
213 }
214}
215
216impl PartialEq<String> for InternedString {
217 fn eq(&self, other: &String) -> bool {
218 self.as_str() == *other
219 }
220}
221
222impl Deref for InternedString {
223 type Target = str;
224
225 fn deref(&self) -> &Self::Target {
226 self.as_str()
227 }
228}
229
230impl Display for InternedString {
231 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
232 self.value.fmt(f)
233 }
234}
235
236impl Default for InternedString {
237 fn default() -> Self {
238 EMPTY.clone()
239 }
240}