statsig_rust/user/
statsig_user_loggable.rs1use super::user_data::UserData;
2use crate::DynamicValue;
3use serde::{ser::SerializeStruct, Deserialize, Serialize};
4use serde_json::Value;
5use std::{collections::HashMap, sync::Arc};
6
7const TAG: &str = "StatsigUserLoggable";
8
9#[derive(Clone, Default)]
10pub struct StatsigUserLoggable {
11 pub data: Arc<UserData>,
12 pub environment: Option<HashMap<String, DynamicValue>>,
13 pub global_custom: Option<HashMap<String, DynamicValue>>,
14}
15
16impl StatsigUserLoggable {
17 pub fn new(
18 user_inner: &Arc<UserData>,
19 environment: Option<HashMap<String, DynamicValue>>,
20 global_custom: Option<HashMap<String, DynamicValue>>,
21 ) -> Self {
22 Self {
23 data: user_inner.clone(),
24 environment,
25 global_custom,
26 }
27 }
28
29 pub fn null() -> Self {
30 Self::default()
31 }
32}
33
34impl Serialize for StatsigUserLoggable {
37 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
38 where
39 S: serde::Serializer,
40 {
41 let mut state = serializer.serialize_struct(TAG, 10)?;
42
43 let data = self.data.as_ref();
44 serialize_data_field(&mut state, "userID", &data.user_id)?;
45 serialize_data_field(&mut state, "customIDs", &data.custom_ids)?;
46 serialize_data_field(&mut state, "email", &data.email)?;
47 serialize_data_field(&mut state, "ip", &data.ip)?;
48 serialize_data_field(&mut state, "userAgent", &data.user_agent)?;
49 serialize_data_field(&mut state, "country", &data.country)?;
50 serialize_data_field(&mut state, "locale", &data.locale)?;
51 serialize_data_field(&mut state, "appVersion", &data.app_version)?;
52
53 serialize_custom_field(&mut state, &data.custom, &self.global_custom)?;
54 serialize_data_field(&mut state, "statsigEnvironment", &self.environment)?;
55
56 state.end()
59 }
60}
61
62impl<'de> Deserialize<'de> for StatsigUserLoggable {
63 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
64 where
65 D: serde::Deserializer<'de>,
66 {
67 let mut value = Value::deserialize(deserializer)?;
68 let env = value["statsigEnvironment"].take();
69 let data = serde_json::from_value::<UserData>(value).map_err(|e| {
70 serde::de::Error::custom(format!("Error deserializing StatsigUserInner: {e}"))
71 })?;
72
73 let environment = serde_json::from_value::<Option<HashMap<String, DynamicValue>>>(env)
74 .map_err(|e| {
75 serde::de::Error::custom(format!("Error deserializing StatsigUserInner: {e}"))
76 })?;
77
78 Ok(StatsigUserLoggable {
79 data: Arc::new(data),
80 environment,
81 global_custom: None, })
83 }
84}
85
86fn serialize_data_field<S, T>(
87 state: &mut S,
88 field: &'static str,
89 value: &Option<T>,
90) -> Result<(), S::Error>
91where
92 S: SerializeStruct,
93 T: Serialize,
94{
95 if let Some(value) = value {
96 state.serialize_field(field, value)?;
97 }
98 Ok(())
99}
100
101fn serialize_custom_field<S>(
102 state: &mut S,
103 custom: &Option<HashMap<String, DynamicValue>>,
104 global_custom: &Option<HashMap<String, DynamicValue>>,
105) -> Result<(), S::Error>
106where
107 S: SerializeStruct,
108{
109 if global_custom.is_none() && custom.is_none() {
110 return Ok(());
111 }
112
113 let mut map = HashMap::new();
114
115 if let Some(global_custom) = global_custom.as_ref() {
116 for (k, v) in global_custom {
117 map.insert(k, v);
118 }
119 }
120
121 if let Some(custom) = custom.as_ref() {
122 for (k, v) in custom {
123 map.insert(k, v);
124 }
125 }
126
127 serialize_data_field(state, "custom", &Some(map))
128}