statsig_rust/evaluation/
evaluator_context.rs1use crate::evaluation::dynamic_value::DynamicValue;
2use crate::evaluation::evaluator_result::EvaluatorResult;
3use crate::event_logging::exposable_string::ExposableString;
4use crate::hashing::HashUtil;
5use crate::spec_store::SpecStoreData;
6use crate::specs_response::spec_types::{Rule, Spec};
7use crate::user::StatsigUserInternal;
8use crate::StatsigErr::StackOverflowError;
9use crate::{OverrideAdapter, StatsigErr};
10use std::collections::HashMap;
11use std::sync::Arc;
12
13const MAX_RECURSIVE_DEPTH: u16 = 300;
14
15pub struct EvaluatorContext<'a> {
16 pub user: &'a StatsigUserInternal<'a, 'a>,
17 pub spec_store_data: &'a SpecStoreData,
18 pub hashing: &'a HashUtil,
19 pub result: EvaluatorResult<'a>,
20 pub nested_count: u16,
21 pub app_id: Option<&'a DynamicValue>,
22 pub override_adapter: Option<&'a Arc<dyn OverrideAdapter>>,
23 pub nested_gate_memo: HashMap<&'a str, (bool, Option<&'a ExposableString>)>,
24}
25
26impl<'a> EvaluatorContext<'a> {
27 pub fn new(
28 user: &'a StatsigUserInternal,
29 spec_store_data: &'a SpecStoreData,
30 hashing: &'a HashUtil,
31 app_id: Option<&'a DynamicValue>,
32 override_adapter: Option<&'a Arc<dyn OverrideAdapter>>,
33 ) -> Self {
34 let result = EvaluatorResult::default();
35
36 Self {
37 user,
38 spec_store_data,
39 hashing,
40 app_id,
41 result,
42 override_adapter,
43 nested_count: 0,
44 nested_gate_memo: HashMap::new(),
45 }
46 }
47
48 pub fn reset_result(&mut self) {
49 self.nested_count = 0;
50 self.result = EvaluatorResult::default();
51 }
52
53 pub fn finalize_evaluation(&mut self, spec: &Spec, rule: Option<&Rule>) {
54 self.result.sampling_rate = rule.and_then(|r| r.sampling_rate);
55 self.result.forward_all_exposures = spec.forward_all_exposures;
56
57 if self.nested_count > 0 {
58 self.nested_count -= 1;
59 return;
60 }
61
62 if self.result.secondary_exposures.is_empty() {
63 return;
64 }
65
66 if self.result.undelegated_secondary_exposures.is_some() {
67 return;
68 }
69
70 self.result.undelegated_secondary_exposures = Some(self.result.secondary_exposures.clone());
71 }
72
73 pub fn prep_for_nested_evaluation(&mut self) -> Result<(), StatsigErr> {
74 self.nested_count += 1;
75
76 self.result.bool_value = false;
77 self.result.json_value = None;
78
79 if self.nested_count > MAX_RECURSIVE_DEPTH {
80 return Err(StackOverflowError);
81 }
82
83 Ok(())
84 }
85}