statsig_rust/hashing/
hash_util.rs

1use serde::{de::Error, Deserialize, Deserializer};
2
3use super::{djb2::djb2, memo_sha_256::MemoSha256};
4use std::fmt::Display;
5
6#[derive(Eq, PartialEq)]
7pub enum HashAlgorithm {
8    Djb2,
9    None,
10    Sha256,
11}
12
13impl HashAlgorithm {
14    #[must_use]
15    pub fn from_string(input: &str) -> Option<Self> {
16        match input {
17            "sha256" | "SHA256" | "Sha256" => Some(HashAlgorithm::Sha256),
18            "djb2" | "DJB2" | "Djb2" => Some(HashAlgorithm::Djb2),
19            "none" | "NONE" | "None" => Some(HashAlgorithm::None),
20            _ => None,
21        }
22    }
23}
24
25impl<'de> Deserialize<'de> for HashAlgorithm {
26    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
27    where
28        D: Deserializer<'de>,
29    {
30        let s = String::deserialize(deserializer)?;
31        HashAlgorithm::from_string(&s).ok_or_else(|| D::Error::custom("Invalid hash algorithm"))
32    }
33}
34
35impl Display for HashAlgorithm {
36    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37        match self {
38            HashAlgorithm::Djb2 => write!(f, "djb2"),
39            HashAlgorithm::None => write!(f, "none"),
40            HashAlgorithm::Sha256 => write!(f, "sha256"),
41        }
42    }
43}
44
45pub struct HashUtil {
46    sha_hasher: MemoSha256,
47}
48
49impl Default for HashUtil {
50    fn default() -> Self {
51        Self::new()
52    }
53}
54
55impl HashUtil {
56    #[must_use]
57    pub fn new() -> Self {
58        Self {
59            sha_hasher: MemoSha256::new(),
60        }
61    }
62
63    pub fn hash(&self, input: &str, hash_algorithm: &HashAlgorithm) -> String {
64        match hash_algorithm {
65            HashAlgorithm::Sha256 => self.sha_hasher.hash_string(input),
66            HashAlgorithm::Djb2 => djb2(input),
67            HashAlgorithm::None => input.to_string(),
68        }
69    }
70
71    pub fn sha256(&self, input: &str) -> String {
72        self.sha_hasher.hash_string(input)
73    }
74
75    pub fn sha256_to_u64(&self, input: &str) -> u64 {
76        let hash = self.sha_hasher.hash_string(input);
77
78        let mut hasher_bytes = [0u8; 8];
79        hasher_bytes.copy_from_slice(&hash.as_bytes()[0..8]);
80
81        u64::from_be_bytes(hasher_bytes)
82    }
83
84    pub fn evaluation_hash(&self, input: &String) -> Option<u64> {
85        self.sha_hasher.compute_hash(input)
86    }
87}