1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
use std::hash::Hasher as _;

pub use ::xxhash_rust::xxh3::Xxh3 as Xxh3Hasher;
use digest::typenum::{U16, U8};
use digest::{FixedOutput, HashMarker, Output, OutputSizeUser, Update};

use crate::common::{impl_hash_wrapper, HashWrapper};

macro_rules! make_hasher {
    ($hash_wrapper:ident, $hasher:ty, $digest:expr, $output_size:ident) => {
        #[derive(Clone, Default)]
        pub struct $hash_wrapper($hasher);

        impl_hash_wrapper!($hash_wrapper, $hasher, $output_size);

        impl Update for $hash_wrapper {
            fn update(&mut self, data: &[u8]) {
                self.0.write(data);
            }
        }

        impl FixedOutput for $hash_wrapper {
            fn finalize_into(self, out: &mut Output<Self>) {
                let result = $digest(&self.0);
                let bytes = result.to_be_bytes();
                out.copy_from_slice(&bytes);
            }
        }
    };
}

make_hasher!(Xxh3_64, Xxh3Hasher, Xxh3Hasher::digest, U8);
make_hasher!(Xxh3_128, Xxh3Hasher, Xxh3Hasher::digest128, U16);

#[cfg(test)]
mod tests {
    use insta::assert_snapshot;
    use xxhash_rust::xxh3::{xxh3_128, xxh3_64};

    use super::{Xxh3_128, Xxh3_64};
    use crate::tests::hash;

    #[test]
    fn test_xxh3_64() {
        let default = xxh3_64(&[]);
        assert_eq!(hash::<Xxh3_64>(""), format!("{default:X}"));
        assert_snapshot!(hash::<Xxh3_64>(""), @"2D06800538D394C2");
        assert_snapshot!(hash::<Xxh3_64>("hello"), @"9555E8555C62DCFD");
    }

    #[test]
    fn test_xxh3_128() {
        let default = xxh3_128(&[]);
        assert_eq!(hash::<Xxh3_128>(""), format!("{default:X}"));
        assert_snapshot!(hash::<Xxh3_128>(""), @"99AA06D3014798D86001C324468D497F");
        assert_snapshot!(hash::<Xxh3_128>("hello"), @"B5E9C1AD071B3E7FC779CFAA5E523818");
    }
}