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