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);