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 self.user_ref.get_unit_id(id_type)
37 }
38
39 pub fn get_user_value(&self, field: &Option<DynamicString>) -> Option<&DynamicValue> {
40 let field = field.as_ref()?;
41
42 let lowered_field = &field.lowercased_value;
43
44 let str_value = match lowered_field as &str {
45 "userid" => &self.user_ref.data.user_id,
46 "email" => &self.user_ref.data.email,
47 "ip" => &self.user_ref.data.ip,
48 "country" => &self.user_ref.data.country,
49 "locale" => &self.user_ref.data.locale,
50 "appversion" => &self.user_ref.data.app_version,
51 "useragent" => &self.user_ref.data.user_agent,
52 _ => &None,
53 };
54
55 if let Some(value) = str_value {
56 if let Some(str_val) = &value.string_value {
57 if !str_val.value.is_empty() {
58 return Some(value);
59 }
60 }
61 }
62
63 if let Some(custom) = &self.user_ref.data.custom {
64 if let Some(found) = custom.get(field.value.as_str()) {
65 return Some(found);
66 }
67 if let Some(lowered_found) = custom.get(lowered_field.as_str()) {
68 return Some(lowered_found);
69 }
70 }
71
72 if let Some(instance) = &self.statsig_instance {
73 if let Some(val) = instance.get_value_from_global_custom_fields(&field.value) {
74 return Some(val);
75 }
76
77 if let Some(val) = instance.get_value_from_global_custom_fields(&field.lowercased_value)
78 {
79 return Some(val);
80 }
81 }
82
83 if let Some(private_attributes) = &self.user_ref.data.private_attributes {
84 if let Some(found) = private_attributes.get(field.value.as_str()) {
85 return Some(found);
86 }
87 if let Some(lowered_found) = private_attributes.get(lowered_field.as_str()) {
88 return Some(lowered_found);
89 }
90 }
91
92 let str_value_alt = match lowered_field as &str {
93 "user_id" => &self.user_ref.data.user_id,
94 "app_version" => &self.user_ref.data.app_version,
95 "user_agent" => &self.user_ref.data.user_agent,
96 _ => &None,
97 };
98
99 if str_value_alt.is_some() {
100 return str_value_alt.as_ref();
101 }
102
103 None
104 }
105
106 pub fn get_value_from_environment(
107 &self,
108 field: &Option<DynamicString>,
109 ) -> Option<DynamicValue> {
110 let field = field.as_ref()?;
111
112 if let Some(result) = self.statsig_instance?.get_from_statsig_env(&field.value) {
113 return Some(result);
114 }
115
116 self.statsig_instance?
117 .get_from_statsig_env(&field.lowercased_value)
118 }
119
120 pub fn to_loggable(&self) -> StatsigUserLoggable {
121 let (environment, global_custom) = match self.statsig_instance {
122 Some(statsig) => (
123 statsig.use_statsig_env(|e| e.cloned()),
124 statsig.use_global_custom_fields(|gc| gc.cloned()),
125 ),
126 None => (None, None),
127 };
128
129 StatsigUserLoggable::new(&self.user_ref.data, environment, global_custom)
130 }
131
132 pub fn get_hashed_private_attributes(&self) -> Option<String> {
133 let private_attributes = match &self.user_ref.data.private_attributes {
134 Some(attrs) => attrs,
135 None => return None,
136 };
137
138 if private_attributes.is_empty() {
139 return None;
140 }
141
142 let mut val: i64 = 0;
143 for (key, value) in private_attributes {
144 let hash_key = match value.string_value {
145 Some(ref s) => key.to_owned() + ":" + &s.value,
146 None => key.to_owned() + ":",
147 };
148 val += djb2_number(&hash_key);
149 val &= 0xFFFF_FFFF;
150 }
151 Some(val.to_string())
152 }
153}