statsig_rust/specs_response/
condition_key.rs

1use std::hash::{Hash, Hasher};
2
3use serde::{Deserialize, Deserializer, Serialize};
4
5/**
6DCS v2 stores conditions in a map. This means that for each evaluation, we do a lookup from
7the Rule.conditions vec to the top level condition_map.
8
9Given that we know the keys are a djb2 hash, we can convert them to u64 numbers during deserialization.
10Having these keys as numbers makes the lookup a lot faster as the "hash" for the HashMap is just the u64 integer.
11
12I have included fallback support for Strings in-case the DCS payload changes in the future
13*/
14
15#[derive(PartialEq, Eq, Debug)]
16pub struct ConditionKey {
17    pub u64_value: Option<u64>,
18    pub string_value: String,
19}
20
21impl<'de> Deserialize<'de> for ConditionKey {
22    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
23    where
24        D: Deserializer<'de>,
25    {
26        let string_value = String::deserialize(deserializer)?;
27        let u64_value = string_value.parse::<u64>().ok();
28        Ok(ConditionKey {
29            u64_value,
30            string_value,
31        })
32    }
33}
34
35impl Serialize for ConditionKey {
36    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
37    where
38        S: serde::Serializer,
39    {
40        serializer.serialize_str(&self.string_value)
41    }
42}
43
44impl Hash for ConditionKey {
45    fn hash<H: Hasher>(&self, state: &mut H) {
46        if let Some(u64_value) = self.u64_value {
47            u64_value.hash(state);
48        } else {
49            self.string_value.hash(state);
50        }
51    }
52}