statsig_rust/evaluation/
dynamic_returnable.rs1use 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_map(value: HashMap<String, JsonValue>) -> Self {
37 let raw_value = match to_raw_value(&value) {
38 Ok(raw_value) => raw_value,
39 Err(e) => {
40 log_e!(TAG, "Failed to convert map to raw value: {}", e);
41 return Self::empty();
42 }
43 };
44
45 let (hash, value) = DynamicReturnable::get_or_create_memoized(Cow::Owned(raw_value));
46 Self { hash, value }
47 }
48
49 pub fn get_bool(&self) -> Option<bool> {
50 match self.value.raw_value.get() {
51 "true" => Some(true),
52 "false" => Some(false),
53 _ => None,
54 }
55 }
56
57 pub fn get_json(&self) -> Option<HashMap<String, JsonValue>> {
58 let raw_json = self.value.raw_value.get();
59
60 match raw_json {
61 "null" | "true" | "false" => None,
62 _ => match serde_json::from_str(raw_json) {
63 Ok(json) => Some(json),
64 Err(e) => {
65 log_e!(TAG, "Failed to parse json: {}. Error: {}", raw_json, e);
66 None
67 }
68 },
69 }
70 }
71
72 pub fn get_hash(&self) -> u64 {
73 self.hash
74 }
75}
76
77impl<'de> Deserialize<'de> for DynamicReturnable {
78 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
79 where
80 D: Deserializer<'de>,
81 {
82 let raw_value_ref: Box<RawValue> = Deserialize::deserialize(deserializer)?;
83 let (hash, value) = DynamicReturnable::get_or_create_memoized(Cow::Owned(raw_value_ref));
84 Ok(DynamicReturnable { hash, value })
85 }
86}
87
88impl Serialize for DynamicReturnable {
89 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
90 where
91 S: Serializer,
92 {
93 self.value.raw_value.serialize(serializer)
94 }
95}
96
97#[derive(Debug, Clone)]
98pub(crate) struct MemoizedValue {
99 pub(crate) raw_value: Box<RawValue>,
100}
101
102impl FromRawValue for MemoizedValue {
103 fn from_raw_value(raw_value: Cow<'_, RawValue>) -> Self {
104 Self {
105 raw_value: raw_value.into_owned(),
106 }
107 }
108}
109
110impl PartialEq for MemoizedValue {
111 fn eq(&self, other: &Self) -> bool {
112 self.raw_value.get() == other.raw_value.get()
113 }
114}