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