statsig_rust/user/
statsig_user_internal.rs1use super::StatsigUserLoggable;
2use crate::evaluation::dynamic_value::DynamicValue;
3use crate::hashing::djb2_number;
4use crate::StatsigUser;
5use crate::{evaluation::dynamic_string::DynamicString, Statsig};
6
7pub type FullUserKey = (
8 u64, u64, u64, u64, u64, u64, u64, Vec<u64>, Vec<u64>, Vec<u64>, Vec<u64>, );
20
21#[derive(Clone)]
22pub struct StatsigUserInternal<'statsig, 'user> {
23 pub user_ref: &'user StatsigUser,
24 pub statsig_instance: Option<&'statsig Statsig>,
25}
26
27impl<'statsig, 'user> StatsigUserInternal<'statsig, 'user> {
28 pub fn new(user: &'user StatsigUser, statsig_instance: Option<&'statsig Statsig>) -> Self {
29 Self {
30 user_ref: user,
31 statsig_instance,
32 }
33 }
34
35 pub fn get_unit_id(&self, id_type: &DynamicString) -> Option<&DynamicValue> {
36 if id_type.lowercased_value.eq("userid") {
37 return self.user_ref.data.user_id.as_ref();
38 }
39
40 let custom_ids = self.user_ref.data.custom_ids.as_ref()?;
41
42 if let Some(custom_id) = custom_ids.get(&id_type.value) {
43 return Some(custom_id);
44 }
45
46 custom_ids.get(&id_type.lowercased_value)
47 }
48
49 pub fn get_user_value(&self, field: &Option<DynamicString>) -> Option<&DynamicValue> {
50 let field = field.as_ref()?;
51
52 let lowered_field = &field.lowercased_value;
53
54 let str_value = match lowered_field as &str {
55 "userid" => &self.user_ref.data.user_id,
56 "email" => &self.user_ref.data.email,
57 "ip" => &self.user_ref.data.ip,
58 "country" => &self.user_ref.data.country,
59 "locale" => &self.user_ref.data.locale,
60 "appversion" => &self.user_ref.data.app_version,
61 "useragent" => &self.user_ref.data.user_agent,
62 _ => &None,
63 };
64
65 if let Some(value) = str_value {
66 if let Some(str_val) = &value.string_value {
67 if !str_val.value.is_empty() {
68 return Some(value);
69 }
70 }
71 }
72
73 if let Some(custom) = &self.user_ref.data.custom {
74 if let Some(found) = custom.get(&field.value) {
75 return Some(found);
76 }
77 if let Some(lowered_found) = custom.get(lowered_field) {
78 return Some(lowered_found);
79 }
80 }
81
82 if let Some(instance) = &self.statsig_instance {
83 if let Some(val) = instance.get_value_from_global_custom_fields(&field.value) {
84 return Some(val);
85 }
86
87 if let Some(val) = instance.get_value_from_global_custom_fields(&field.lowercased_value)
88 {
89 return Some(val);
90 }
91 }
92
93 if let Some(private_attributes) = &self.user_ref.data.private_attributes {
94 if let Some(found) = private_attributes.get(&field.value) {
95 return Some(found);
96 }
97 if let Some(lowered_found) = private_attributes.get(lowered_field) {
98 return Some(lowered_found);
99 }
100 }
101
102 let str_value_alt = match lowered_field as &str {
103 "user_id" => &self.user_ref.data.user_id,
104 "app_version" => &self.user_ref.data.app_version,
105 "user_agent" => &self.user_ref.data.user_agent,
106 _ => &None,
107 };
108
109 if str_value_alt.is_some() {
110 return str_value_alt.as_ref();
111 }
112
113 None
114 }
115
116 pub fn get_value_from_environment(
117 &self,
118 field: &Option<DynamicString>,
119 ) -> Option<DynamicValue> {
120 let field = field.as_ref()?;
121
122 if let Some(result) = self.statsig_instance?.get_from_statsig_env(&field.value) {
123 return Some(result);
124 }
125
126 self.statsig_instance?
127 .get_from_statsig_env(&field.lowercased_value)
128 }
129
130 pub fn to_loggable(&self) -> StatsigUserLoggable {
131 let (environment, global_custom) = match self.statsig_instance {
132 Some(statsig) => (
133 statsig.use_statsig_env(|e| e.cloned()),
134 statsig.use_global_custom_fields(|gc| gc.cloned()),
135 ),
136 None => (None, None),
137 };
138
139 StatsigUserLoggable::new(&self.user_ref.data, environment, global_custom)
140 }
141
142 pub fn get_hashed_private_attributes(&self) -> Option<String> {
143 let private_attributes = match &self.user_ref.data.private_attributes {
144 Some(attrs) => attrs,
145 None => return None,
146 };
147
148 if private_attributes.is_empty() {
149 return None;
150 }
151
152 let mut val: i64 = 0;
153 for (key, value) in private_attributes {
154 let hash_key = match value.string_value {
155 Some(ref s) => key.to_owned() + ":" + &s.value,
156 None => key.to_owned() + ":",
157 };
158 val += djb2_number(&hash_key);
159 val &= 0xFFFF_FFFF;
160 }
161 Some(val.to_string())
162 }
163}