statsig_rust/event_logging/
exposable_string.rs

1use crate::{hashing::ahash_str, log_e};
2use serde::{Deserialize, Deserializer, Serialize, Serializer};
3use serde_json::value::{to_raw_value, RawValue};
4use std::{borrow::Cow, sync::Arc};
5
6lazy_static::lazy_static! {
7    pub static ref EMPTY_STRING: ExposableString = ExposableString::from_str_ref("");
8    pub static ref DEFAULT_RULE: ExposableString = ExposableString::from_str_ref("default");
9    pub static ref DISABLED_RULE: ExposableString = ExposableString::from_str_ref("disabled");
10}
11
12const TAG: &str = "ExposableString";
13
14#[derive(Debug, Clone)]
15pub struct ExposableString {
16    pub hash_value: u64,
17
18    // DO NOT MAKE "pub" OR FIRED
19    raw_value: Arc<Box<RawValue>>,
20}
21
22impl ExposableString {
23    pub fn from_str_parts(parts: &[&str]) -> Self {
24        let mut value = String::new();
25        for v in parts {
26            value.push_str(v);
27        }
28
29        Self::from_str_ref(&value)
30    }
31
32    pub fn from_str_ref(value: &str) -> Self {
33        let hash_value = ahash_str(value);
34
35        let raw_value: Box<RawValue> = match to_raw_value(value) {
36            Ok(raw_value) => raw_value,
37            Err(e) => {
38                log_e!(
39                    TAG,
40                    "Failed to convert string to raw value: {}, {}",
41                    e,
42                    value
43                );
44                return EMPTY_STRING.clone();
45            }
46        };
47
48        Self {
49            raw_value: Arc::new(raw_value),
50            hash_value,
51        }
52    }
53
54    pub fn from_raw_value(raw_value: Box<RawValue>) -> Self {
55        let hash_value = ahash_str(str_from_raw_value(&raw_value));
56        Self {
57            raw_value: Arc::new(raw_value),
58            hash_value,
59        }
60    }
61
62    pub fn as_str(&self) -> &str {
63        str_from_raw_value(&self.raw_value)
64    }
65
66    /// Clones the value out of the Arc. This is not performant.
67    /// Please only use this if we are giving a value to a caller outside of this library.
68    /// Consider using the `as_str` method instead.
69    pub fn unperformant_to_string(&self) -> String {
70        self.as_str().to_owned()
71    }
72}
73
74impl Default for ExposableString {
75    fn default() -> Self {
76        EMPTY_STRING.clone()
77    }
78}
79
80impl<'de> Deserialize<'de> for ExposableString {
81    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
82    where
83        D: Deserializer<'de>,
84    {
85        let value = Cow::<'de, str>::deserialize(deserializer)?;
86        Ok(Self::from_str_ref(&value))
87    }
88}
89
90impl Serialize for ExposableString {
91    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
92    where
93        S: Serializer,
94    {
95        self.raw_value.serialize(serializer)
96    }
97}
98
99impl PartialEq for ExposableString {
100    fn eq(&self, other: &Self) -> bool {
101        self.hash_value == other.hash_value
102    }
103}
104
105impl Eq for ExposableString {}
106
107fn str_from_raw_value(raw_value: &RawValue) -> &str {
108    let value = raw_value.get();
109    if value.len() >= 2 {
110        &value[1..value.len() - 1]
111    } else {
112        ""
113    }
114}