statsig_rust/evaluation/
evaluation_types.rs1use super::dynamic_returnable::DynamicReturnable;
2use crate::{event_logging::exposable_string::ExposableString, 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: ExposableString,
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: ExposableString,
42 pub rule_id: ExposableString,
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 pub id_type: InternedString,
104 pub value: bool,
105}
106
107#[derive(Serialize, Deserialize, Clone)]
108pub struct DynamicConfigEvaluation {
109 #[serde(flatten)]
110 pub base: BaseEvaluation,
111
112 pub id_type: InternedString,
113 pub value: DynamicReturnable,
114
115 pub group: ExposableString,
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 pub id_type: InternedString,
128 pub value: DynamicReturnable,
129
130 pub group: ExposableString,
132 pub is_device_based: bool,
133
134 #[serde(skip_serializing_if = "is_false")]
135 pub is_in_layer: bool,
136
137 #[serde(skip_serializing_if = "Option::is_none")]
138 pub explicit_parameters: Option<Vec<InternedString>>,
139
140 #[serde(skip_serializing_if = "Option::is_none")]
141 pub group_name: Option<InternedString>,
142
143 #[serde(skip_serializing_if = "Option::is_none")]
144 pub is_experiment_active: Option<bool>,
145
146 #[serde(skip_serializing_if = "Option::is_none")]
147 pub is_user_in_experiment: Option<bool>,
148 #[serde(skip_serializing_if = "Option::is_none")]
149 pub undelegated_secondary_exposures: Option<Vec<SecondaryExposure>>,
150}
151
152#[derive(Serialize, Deserialize, Clone)]
153#[serde(untagged)]
154pub enum AnyConfigEvaluation {
155 DynamicConfig(DynamicConfigEvaluation),
156 Experiment(ExperimentEvaluation),
157}
158
159#[derive(Serialize, Deserialize, Clone)]
160pub struct LayerEvaluation {
161 #[serde(flatten)]
162 pub base: BaseEvaluation,
163
164 pub value: DynamicReturnable,
165
166 pub id_type: InternedString,
167
168 pub group: InternedString,
170 pub is_device_based: bool,
171
172 #[serde(skip_serializing_if = "Option::is_none")]
173 pub group_name: Option<InternedString>,
174
175 #[serde(skip_serializing_if = "Option::is_none")]
176 pub is_experiment_active: Option<bool>,
177
178 #[serde(skip_serializing_if = "Option::is_none")]
179 pub is_user_in_experiment: Option<bool>,
180
181 #[serde(skip_serializing_if = "Option::is_none")]
182 pub allocated_experiment_name: Option<InternedString>,
183 pub explicit_parameters: Vec<InternedString>,
184 #[serde(skip_serializing_if = "Option::is_none")]
185 pub undelegated_secondary_exposures: Option<Vec<SecondaryExposure>>,
186}