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_STRING: 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 static ref SALT_STRING: InternedString = InternedString::from_string("salt".to_string());
26}
27
28const TAG: &str = "InternedString";
29
30#[derive(Clone, Debug, Eq)]
31pub struct InternedString {
32 pub hash: u64,
33 pub value: Arc<String>,
34}
35
36impl InternedString {
37 pub fn from_str_ref(value: &str) -> Self {
38 let hash = hashing::hash_one(value);
39 let value = InternedString::get_or_create_memoized_string(hash, Cow::Borrowed(value));
40 Self { hash, value }
41 }
42
43 pub fn from_string(value: String) -> Self {
44 let hash = hashing::hash_one(value.as_str());
45 let value = InternedString::get_or_create_memoized_string(hash, Cow::Owned(value));
46 Self { hash, value }
47 }
48
49 pub fn from_bool(value: bool) -> Self {
50 if value {
51 TRUE_STRING.clone()
52 } else {
53 FALSE_STRING.clone()
54 }
55 }
56
57 pub fn from_dynamic_string(value: &DynamicString) -> Self {
58 let hash = value.hash_value;
59 let value =
60 InternedString::get_or_create_memoized_string(hash, Cow::Borrowed(&value.value));
61 Self { hash, value }
62 }
63
64 pub fn as_str(&self) -> &str {
65 self.value.as_str()
66 }
67
68 pub fn unperformant_to_string(&self) -> String {
71 self.value.to_string()
72 }
73
74 pub fn empty_ref() -> &'static Self {
75 &EMPTY_STRING
76 }
77
78 pub fn empty() -> Self {
79 EMPTY_STRING.clone()
80 }
81
82 pub fn salt_ref() -> &'static Self {
83 &SALT_STRING
84 }
85
86 fn get_or_create_memoized_string(hash: u64, input: Cow<'_, str>) -> Arc<String> {
87 if let Some(value) = INTERNED_STORE.try_get_interned_value(hash) {
88 return value;
89 }
90
91 let value = input.to_string();
92 let value_arc = Arc::new(value);
93 INTERNED_STORE.set_interned_value(hash, &value_arc);
94 value_arc
95 }
96}
97
98impl_interned_value!(InternedString, String);
99
100impl<'de> Deserialize<'de> for InternedString {
101 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
102 where
103 D: Deserializer<'de>,
104 {
105 #[derive(Deserialize)]
106 #[serde(untagged)]
107 enum CowString<'a> {
108 #[serde(borrow)]
109 Borrowed(&'a str), Owned(String), }
112
113 let raw: CowString<'de> = CowString::deserialize(deserializer)?;
114 match raw {
115 CowString::Borrowed(raw) => {
116 let hash = hashing::hash_one(raw);
117 let value = InternedString::get_or_create_memoized_string(hash, Cow::Borrowed(raw));
118 Ok(InternedString { hash, value })
119 }
120 CowString::Owned(raw) => {
121 let hash = hashing::hash_one(raw.as_str());
122 let value = InternedString::get_or_create_memoized_string(hash, Cow::Owned(raw));
123 Ok(InternedString { hash, value })
124 }
125 }
126 }
127}
128
129impl Serialize for InternedString {
130 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
131 where
132 S: Serializer,
133 {
134 self.value.serialize(serializer)
135 }
136}
137
138impl FromRawValue for String {
139 fn from_raw_value(raw_value: Cow<'_, RawValue>) -> Self {
140 match serde_json::from_str(raw_value.get()) {
141 Ok(value) => value,
142 Err(e) => {
143 log_e!(TAG, "Failed to convert raw value to String: {}", e);
144 String::new()
145 }
146 }
147 }
148}
149
150impl PartialEq for InternedString {
151 fn eq(&self, other: &Self) -> bool {
152 self.hash == other.hash
153 }
154}
155
156impl Hash for InternedString {
157 fn hash<H: Hasher>(&self, state: &mut H) {
158 self.hash.hash(state);
159 }
160}
161
162impl PartialEq<&str> for InternedString {
163 fn eq(&self, other: &&str) -> bool {
164 self.as_str() == *other
165 }
166}
167
168impl PartialEq<str> for InternedString {
169 fn eq(&self, other: &str) -> bool {
170 self.as_str() == other
171 }
172}
173
174impl PartialEq<String> for InternedString {
175 fn eq(&self, other: &String) -> bool {
176 self.as_str() == *other
177 }
178}
179
180impl Deref for InternedString {
181 type Target = str;
182
183 fn deref(&self) -> &Self::Target {
184 self.as_str()
185 }
186}
187
188impl Display for InternedString {
189 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
190 self.value.fmt(f)
191 }
192}
193
194impl Default for InternedString {
195 fn default() -> Self {
196 EMPTY_STRING.clone()
197 }
198}