statsig_rust/evaluation/
evaluation_types.rs1use super::dynamic_returnable::DynamicReturnable;
2use crate::{
3 evaluation::secondary_exposure_key::SecondaryExposureKey, interned_string::InternedString,
4};
5use serde::{Deserialize, Serialize};
6
7pub fn is_false(v: &bool) -> bool {
8 !(*v)
9}
10
11#[derive(Serialize, Deserialize, Clone, Debug)]
12#[serde(rename_all = "camelCase")]
13pub struct SecondaryExposure {
14 pub gate: InternedString,
15 pub gate_value: InternedString,
16 #[serde(rename = "ruleID")]
17 pub rule_id: InternedString,
18}
19
20impl SecondaryExposure {
21 pub fn get_dedupe_key(&self) -> String {
22 let mut key = String::new();
23 key += &self.gate;
24 key += "|";
25 key += &self.gate_value;
26 key += "|";
27 key += self.rule_id.as_str();
28 key
29 }
30}
31
32impl From<&SecondaryExposure> for SecondaryExposureKey {
33 fn from(val: &SecondaryExposure) -> Self {
34 SecondaryExposureKey {
35 gate_name_hash: val.gate.hash,
36 rule_id_hash: val.rule_id.hash,
37 gate_value_hash: val.gate_value.hash,
38 }
39 }
40}
41
42#[derive(Serialize, Deserialize, Clone, Debug, Default)]
43pub struct ExtraExposureInfo {
44 pub sampling_rate: Option<u64>,
45 pub forward_all_exposures: Option<bool>,
46 pub has_seen_analytical_gates: Option<bool>,
47 pub override_config_name: Option<String>,
48 pub version: Option<u32>,
49}
50
51#[derive(Serialize, Deserialize, Clone)]
52pub struct BaseEvaluation {
53 pub name: InternedString,
54 pub rule_id: InternedString,
55 pub secondary_exposures: Vec<SecondaryExposure>,
56
57 #[serde(skip_serializing)]
58 pub(crate) exposure_info: Option<ExtraExposureInfo>,
59}
60
61pub enum AnyEvaluation<'a> {
62 FeatureGate(&'a GateEvaluation),
63 DynamicConfig(&'a DynamicConfigEvaluation),
64 Experiment(&'a ExperimentEvaluation),
65 Layer(&'a LayerEvaluation),
66}
67
68impl AnyEvaluation<'_> {
69 pub fn get_base_result(&self) -> &BaseEvaluation {
70 match self {
71 AnyEvaluation::FeatureGate(gate) => &gate.base,
72 AnyEvaluation::DynamicConfig(config) => &config.base,
73 AnyEvaluation::Experiment(experiment) => &experiment.base,
74 AnyEvaluation::Layer(layer) => &layer.base,
75 }
76 }
77
78 pub fn get_gate_bool_value(&self) -> bool {
79 match self {
80 AnyEvaluation::FeatureGate(eval) => eval.value,
81 _ => false, }
83 }
84}
85
86impl<'a> From<&'a LayerEvaluation> for AnyEvaluation<'a> {
87 fn from(layer_eval: &'a LayerEvaluation) -> Self {
88 AnyEvaluation::Layer(layer_eval)
89 }
90}
91
92impl<'a> From<&'a GateEvaluation> for AnyEvaluation<'a> {
93 fn from(gate_eval: &'a GateEvaluation) -> Self {
94 AnyEvaluation::FeatureGate(gate_eval)
95 }
96}
97
98impl<'a> From<&'a ExperimentEvaluation> for AnyEvaluation<'a> {
99 fn from(experiment_eval: &'a ExperimentEvaluation) -> Self {
100 AnyEvaluation::Experiment(experiment_eval)
101 }
102}
103
104impl<'a> From<&'a DynamicConfigEvaluation> for AnyEvaluation<'a> {
105 fn from(dynamic_config_evalation: &'a DynamicConfigEvaluation) -> Self {
106 AnyEvaluation::DynamicConfig(dynamic_config_evalation)
107 }
108}
109
110#[derive(Serialize, Deserialize, Clone)]
111pub struct GateEvaluation {
112 #[serde(flatten)]
113 pub base: BaseEvaluation,
114
115 #[serde(skip_serializing_if = "Option::is_none")]
116 pub id_type: Option<InternedString>,
117 pub value: bool,
118}
119
120#[derive(Serialize, Deserialize, Clone)]
121pub struct DynamicConfigEvaluation {
122 #[serde(flatten)]
123 pub base: BaseEvaluation,
124
125 #[serde(skip_serializing_if = "Option::is_none")]
126 pub id_type: Option<InternedString>,
127 pub value: DynamicReturnable,
128
129 pub is_device_based: bool,
130
131 pub passed: bool,
132}
133
134#[derive(Serialize, Deserialize, Clone)]
135pub struct ExperimentEvaluation {
136 #[serde(flatten)]
137 pub base: BaseEvaluation,
138
139 #[serde(skip_serializing_if = "Option::is_none")]
140 pub id_type: Option<InternedString>,
141 pub value: DynamicReturnable,
142
143 pub is_device_based: bool,
144
145 #[serde(skip_serializing_if = "is_false")]
146 pub is_in_layer: bool,
147
148 #[serde(skip_serializing_if = "Option::is_none")]
149 pub explicit_parameters: Option<Vec<InternedString>>,
150
151 #[serde(skip_serializing_if = "Option::is_none")]
152 pub group_name: Option<InternedString>,
153
154 #[serde(skip_serializing_if = "Option::is_none")]
155 pub is_experiment_active: Option<bool>,
156
157 #[serde(skip_serializing_if = "Option::is_none")]
158 pub is_user_in_experiment: Option<bool>,
159 #[serde(skip_serializing_if = "Option::is_none")]
160 pub undelegated_secondary_exposures: Option<Vec<SecondaryExposure>>,
161}
162
163#[derive(Serialize, Deserialize, Clone)]
164#[serde(untagged)]
165pub enum AnyConfigEvaluation {
166 DynamicConfig(DynamicConfigEvaluation),
167 Experiment(ExperimentEvaluation),
168}
169
170#[derive(Serialize, Deserialize, Clone)]
171pub struct LayerEvaluation {
172 #[serde(flatten)]
173 pub base: BaseEvaluation,
174
175 pub value: DynamicReturnable,
176
177 #[serde(skip_serializing_if = "Option::is_none")]
178 pub id_type: Option<InternedString>,
179
180 pub is_device_based: bool,
181
182 #[serde(skip_serializing_if = "Option::is_none")]
183 pub group_name: Option<InternedString>,
184
185 #[serde(skip_serializing_if = "Option::is_none")]
186 pub is_experiment_active: Option<bool>,
187
188 #[serde(skip_serializing_if = "Option::is_none")]
189 pub is_user_in_experiment: Option<bool>,
190
191 #[serde(skip_serializing_if = "Option::is_none")]
192 pub allocated_experiment_name: Option<InternedString>,
193 pub explicit_parameters: Vec<InternedString>,
194 #[serde(skip_serializing_if = "Option::is_none")]
195 pub undelegated_secondary_exposures: Option<Vec<SecondaryExposure>>,
196}