growthbook-rust 0.2.1

Official Growthbook Rust SDK
Documentation
use crate::condition::eval_context::{ConditionEvalContext, SavedGroups};
use crate::condition::use_case::ConditionsMatchesAttributes;
use crate::coverage::model::Coverage;
use crate::dto::GrowthBookFeatureRuleForce;
use crate::extensions::FindGrowthBookAttribute;
use crate::model_public::{FeatureResult, GrowthBookAttribute};

impl GrowthBookFeatureRuleForce {
    pub fn get_match_value(
        &self,
        feature_name: &str,
        user_attributes: &Vec<GrowthBookAttribute>,
        saved_groups: &SavedGroups,
    ) -> Option<FeatureResult> {
        // Note: `filters` are evaluated once in the rule loop (get_value) for
        // every rule kind, so the force path no longer checks them here.
        if let Some(feature_attributes) = self.conditions() {
            if feature_attributes.matches(&ConditionEvalContext::new(user_attributes, saved_groups)) {
                self.check_range_or_force(feature_name, user_attributes)
            } else {
                None
            }
        } else {
            self.check_range_or_force(feature_name, user_attributes)
        }
    }

    fn check_range_or_force(
        &self,
        feature_name: &str,
        user_attributes: &Vec<GrowthBookAttribute>,
    ) -> Option<FeatureResult> {
        if let Some(range) = self.range() {
            let seed = self.seed.clone().unwrap_or(feature_name.to_string());

            // Resolve the hash attribute like the rollout path (and JS
            // `getHashAttribute`): the rule's `hashAttribute` if the user has it,
            // otherwise `fallbackAttribute` (defaulting to "id"). Previously this
            // hardcoded "id", ignoring `hashAttribute` entirely.
            if let Some(hash_attribute) = &self.hash_attribute {
                if let Some(user_value) = user_attributes.find_value(hash_attribute) {
                    return Coverage::check(&user_value, None, Some(range), &seed, self.hash_version, self.force.clone());
                }
            }

            let fallback_attribute = self.get_fallback_attribute();
            if let Some(user_value) = user_attributes.find_value(&fallback_attribute) {
                Coverage::check(&user_value, None, Some(range), &seed, self.hash_version, self.force.clone())
            } else {
                None
            }
        } else {
            Some(FeatureResult::force(self.force.clone()))
        }
    }
}