Skip to main content

statsig_rust/evaluation/
dynamic_returnable.rs

1use std::{borrow::Cow, collections::HashMap, sync::Arc};
2
3use serde::{Deserialize, Deserializer, Serialize, Serializer};
4use serde_json::{
5    value::{to_raw_value, RawValue},
6    Value as JsonValue,
7};
8
9use crate::{impl_interned_value, interned_value_store::FromRawValue, log_e};
10
11const TAG: &str = "DynamicReturnable";
12
13lazy_static::lazy_static! {
14    static ref EMPTY_DYNAMIC_RETURNABLE: DynamicReturnable = DynamicReturnable {
15        hash: 0,
16        value: Arc::new(MemoizedValue {
17            raw_value: RawValue::NULL.to_owned(),
18        }),
19    };
20
21}
22
23#[derive(Clone, PartialEq, Debug)]
24pub struct DynamicReturnable {
25    hash: u64,
26    value: Arc<MemoizedValue>,
27}
28
29impl_interned_value!(DynamicReturnable, MemoizedValue);
30
31impl DynamicReturnable {
32    pub fn empty() -> Self {
33        EMPTY_DYNAMIC_RETURNABLE.clone()
34    }
35
36    pub fn from_bool(value: bool) -> Self {
37        let raw_value = match value {
38            true => RawValue::TRUE,
39            false => RawValue::FALSE,
40        };
41
42        let (hash, value) = DynamicReturnable::get_or_create_memoized(Cow::Borrowed(raw_value));
43        Self { hash, value }
44    }
45
46    pub fn from_map(value: HashMap<String, JsonValue>) -> Self {
47        let raw_value = match to_raw_value(&value) {
48            Ok(raw_value) => raw_value,
49            Err(e) => {
50                log_e!(TAG, "Failed to convert map to raw value: {}", e);
51                return Self::empty();
52            }
53        };
54
55        let (hash, value) = DynamicReturnable::get_or_create_memoized(Cow::Owned(raw_value));
56        Self { hash, value }
57    }
58
59    pub fn get_bool(&self) -> Option<bool> {
60        match self.value.raw_value.get() {
61            "true" => Some(true),
62            "false" => Some(false),
63            _ => None,
64        }
65    }
66
67    pub fn get_json(&self) -> Option<HashMap<String, JsonValue>> {
68        let raw_json = self.value.raw_value.get();
69
70        match raw_json {
71            "null" | "true" | "false" => None,
72            _ => match serde_json::from_str(raw_json) {
73                Ok(json) => Some(json),
74                Err(e) => {
75                    log_e!(TAG, "Failed to parse json: {}. Error: {}", raw_json, e);
76                    None
77                }
78            },
79        }
80    }
81
82    pub fn get_hash(&self) -> u64 {
83        self.hash
84    }
85}
86
87impl<'de> Deserialize<'de> for DynamicReturnable {
88    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
89    where
90        D: Deserializer<'de>,
91    {
92        let raw_value_ref: Box<RawValue> = Deserialize::deserialize(deserializer)?;
93        let (hash, value) = DynamicReturnable::get_or_create_memoized(Cow::Owned(raw_value_ref));
94        Ok(DynamicReturnable { hash, value })
95    }
96}
97
98impl Serialize for DynamicReturnable {
99    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
100    where
101        S: Serializer,
102    {
103        self.value.raw_value.serialize(serializer)
104    }
105}
106
107#[derive(Debug, Clone)]
108pub(crate) struct MemoizedValue {
109    pub(crate) raw_value: Box<RawValue>,
110}
111
112impl FromRawValue for MemoizedValue {
113    fn from_raw_value(raw_value: Cow<'_, RawValue>) -> Self {
114        Self {
115            raw_value: raw_value.into_owned(),
116        }
117    }
118}
119
120impl PartialEq for MemoizedValue {
121    fn eq(&self, other: &Self) -> bool {
122        self.raw_value.get() == other.raw_value.get()
123    }
124}