statsig_rust/evaluation/
evaluator_context.rs

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