Skip to main content

axhash_core/
lib.rs

1#![cfg_attr(not(any(feature = "std", test)), no_std)]
2
3mod bytes;
4mod constants;
5mod hasher;
6mod math;
7mod memory;
8
9pub use hasher::{AxBuildHasher, AxHasher, axhash, axhash_of, axhash_of_seeded, axhash_seeded};
10
11#[derive(Clone, Copy, Debug, Eq, PartialEq)]
12pub enum RuntimeBackend {
13    Scalar,
14    Aarch64AesNeon,
15    X86_64AesAvx2,
16}
17
18#[inline(always)]
19pub fn runtime_backend() -> RuntimeBackend {
20    match bytes::selected_backend() {
21        bytes::Backend::Scalar => RuntimeBackend::Scalar,
22        #[cfg(target_arch = "aarch64")]
23        bytes::Backend::Aarch64AesNeon => RuntimeBackend::Aarch64AesNeon,
24        #[cfg(target_arch = "x86_64")]
25        bytes::Backend::X86_64AesAvx2 => RuntimeBackend::X86_64AesAvx2,
26    }
27}
28
29#[inline(always)]
30pub fn runtime_has_aes() -> bool {
31    runtime_backend() != RuntimeBackend::Scalar
32}
33
34#[cfg(test)]
35mod tests {
36    use super::{AxHasher, RuntimeBackend, axhash, axhash_of, axhash_of_seeded, axhash_seeded};
37    use core::hash::{Hash, Hasher};
38
39    #[derive(Hash)]
40    struct DemoRecord {
41        id: u64,
42        shard: u32,
43        flags: u32,
44    }
45
46    #[test]
47    fn hash_is_deterministic_for_bytes() {
48        let data = b"axhash regression seed";
49        let a = axhash_seeded(data, 0x1234_5678_9abc_def0);
50        let b = axhash_seeded(data, 0x1234_5678_9abc_def0);
51        assert_eq!(a, b);
52    }
53
54    #[test]
55    fn hash_changes_when_seed_changes() {
56        let data = b"same payload different seed";
57        let a = axhash_seeded(data, 1);
58        let b = axhash_seeded(data, 2);
59        assert_ne!(a, b);
60    }
61
62    #[test]
63    fn hash_trait_path_is_deterministic() {
64        let record = DemoRecord {
65            id: 42,
66            shard: 7,
67            flags: 3,
68        };
69        let a = axhash_of_seeded(&record, 0xdead_beef);
70        let b = axhash_of_seeded(&record, 0xdead_beef);
71        assert_eq!(a, b);
72    }
73
74    #[test]
75    fn primitive_writes_produce_a_stable_finish() {
76        let mut hasher = AxHasher::new_with_seed(0x4444);
77        hasher.write_u64(0x0102_0304_0506_0708);
78        hasher.write_u32(0xaabb_ccdd);
79        hasher.write_u16(0xeeff);
80        hasher.write_u8(0x11);
81        let value = hasher.finish();
82        assert_ne!(value, 0);
83    }
84
85    #[test]
86    fn test_axhash_default_seed() {
87        let data = b"default seed test";
88        let a = axhash(data);
89        let b = axhash_seeded(data, 0);
90        assert_eq!(a, b);
91    }
92
93    #[test]
94    fn test_axhash_of_default_seed() {
95        let record = DemoRecord {
96            id: 1,
97            shard: 2,
98            flags: 3,
99        };
100        let a = axhash_of(&record);
101        let b = axhash_of_seeded(&record, 0);
102        assert_eq!(a, b);
103    }
104
105    #[test]
106    fn runtime_backend_smoke_test() {
107        match super::runtime_backend() {
108            RuntimeBackend::Scalar
109            | RuntimeBackend::Aarch64AesNeon
110            | RuntimeBackend::X86_64AesAvx2 => {}
111        }
112    }
113}