Skip to main content

azathoth_utils/
hasher.rs

1/// Represents different forms of a function identifier that can be used for hashing.
2///
3/// This enum allows identifying a function either by:
4/// - A precomputed 32-bit hash value (`Hashed`)
5/// - A string slice containing the function name (`Name`)
6/// - A raw byte slice (`Bytes`)
7///
8/// Lifetime `'a` is used to ensure that borrowed data (`&str`, `&[u8]`) outlives the identifier.
9pub enum FuncIdentifier<'a> {
10    /// A precomputed 32-bit hash value.
11    Hashed(u32),
12    /// A borrowed string slice representing the function name.
13    Name(&'a str),
14    /// A borrowed byte slice representing the function name.
15    Bytes(&'a [u8]),
16}
17
18
19impl<'a> From<u32> for FuncIdentifier<'a> {
20    #[inline(always)]
21    fn from(value: u32) -> Self {
22        Self::Hashed(value)
23    }
24}
25
26impl<'a> From<&'a str> for FuncIdentifier<'a> {
27    fn from(value: &'a str) -> Self {
28        Self::Name(value)
29    }
30}
31
32impl<'a> From<&'a [u8]> for FuncIdentifier<'a> {
33    fn from(value: &'a [u8]) -> Self {
34        Self::Bytes(value)
35    }
36}
37
38/// A trait that defines a hashing interface for converting function identifiers (strings or bytes)
39/// into a 32-bit hash value.
40///
41/// Types implementing this trait can be used as hashing strategies for function name resolution.
42pub trait Hasher {
43    /// Hashes a function name (string slice) into a 32-bit hash value.
44    ///
45    /// # Returns
46    /// A 32-bit hash of the input name.
47    fn hash(&self, name: &str) -> u32;
48    /// Hashes a byte slice into a 32-bit hash value.
49    ///
50    /// This is a default implementation that attempts to convert the byte slice to a UTF-8 string.
51    /// If successful, it delegates to the [`hash`] function.
52    /// If not valid UTF-8, it performs a fallback rotation-based hash on raw bytes.
53    ///
54    /// # Returns
55    /// A 32-bit hash of the input bytes.
56    fn hash_bytes(&self, bytes: &[u8]) -> u32 {
57        match core::str::from_utf8(bytes) {
58            Ok(s) => self.hash(s),
59            Err(_) => {
60                let mut val = 0u32;
61                for &b in bytes {
62                    val = val.wrapping_add(b as u32).rotate_left(5);
63                }
64                val
65            }
66        }
67    }
68}
69
70impl<F> Hasher for F
71where
72    F: for<'a> Fn(&'a str) -> u32,
73{
74    #[inline(always)]
75    fn hash(&self, name: &str) -> u32 {
76        self(name)
77    }
78}
79
80
81macro_rules! impl_hasher_tuple {
82    ($( $($T:ident),+ );+ $(;)?) => {
83        $(
84            #[allow(non_snake_case)]
85            impl<F, $($T),+> Hasher for (F, $($T),+)
86            where
87                F: Fn(&str, $($T),+) -> u32,
88                $( $T: Copy ),+
89            {
90                #[inline(always)]
91                fn hash(&self, name: &str) -> u32 {
92                    let (f, $($T),+) = self;
93                    (f)(name, $( *$T ),+)
94                }
95            }
96        )+
97    }
98}
99
100impl_hasher_tuple!(
101    A;
102    A, B;
103    A, B, C;
104    A, B, C, D
105);