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