1#![warn(unsafe_code)]
2#![cfg_attr(not(feature = "std"), no_std)]
3
4#[cfg(feature = "std")]
5use std::{
6 default::Default,
7 hash::{BuildHasherDefault, Hasher},
8};
9
10#[cfg(not(feature = "std"))]
11use core::{
12 default::Default,
13 hash::{BuildHasherDefault, Hasher},
14};
15
16#[cfg(feature = "std")]
17use std::collections::{HashMap, HashSet};
18
19pub struct JoaatHasher(u32);
20
21impl Default for JoaatHasher {
22 #[inline]
23 fn default() -> Self {
24 Self(0)
25 }
26}
27
28impl JoaatHasher {
29 #[inline]
31 #[must_use]
32 pub const fn with_initial_hash(hash: u32) -> Self {
33 Self(hash)
34 }
35}
36
37impl Hasher for JoaatHasher {
38 #[inline]
39 fn finish(&self) -> u64 {
40 let mut hash = self.0;
41 hash = hash.wrapping_add(hash.wrapping_shl(3));
42 hash ^= hash.wrapping_shr(11);
43 hash = hash.wrapping_add(hash.wrapping_shl(15));
44 hash as _
45 }
46
47 #[inline]
48 fn write(&mut self, bytes: &[u8]) {
49 for byte in bytes.iter() {
50 self.0 = self.0.wrapping_add(u32::from(*byte));
51 self.0 = self.0.wrapping_add(self.0.wrapping_shl(10));
52 self.0 ^= self.0.wrapping_shr(6);
53 }
54 }
55}
56
57pub type JoaatBuildHasher = BuildHasherDefault<JoaatHasher>;
59
60#[inline]
62#[must_use]
63pub fn hash_iter<I: Iterator<Item = u8>>(input: I) -> u32 {
64 let mut hasher = JoaatHasher::default();
65
66 for byte in input {
67 hasher.write_u8(byte);
68 }
69
70 hasher.finish() as _
71}
72
73#[inline]
75#[must_use]
76pub fn hash_ascii_lowercase(bytes: &[u8]) -> u32 {
77 hash_iter(bytes.iter().map(|c| c.to_ascii_lowercase()))
78}
79
80#[inline]
82#[must_use]
83pub fn hash_bytes(bytes: &[u8]) -> u32 {
84 let mut hasher = JoaatHasher::default();
85 hasher.write(bytes);
86 hasher.finish() as _
87}
88
89#[cfg(feature = "std")]
91pub type JoaatHashMap<K, V> = HashMap<K, V, JoaatBuildHasher>;
92
93#[cfg(feature = "std")]
95pub type JoaatHashSet<T> = HashSet<T, JoaatBuildHasher>;
96
97#[cfg(test)]
98#[allow(clippy::unreadable_literal)]
99mod tests {
100 use super::*;
101
102 #[test]
103 fn test() {
104 assert_eq!(hash_bytes(b""), 0);
105 assert_eq!(hash_bytes(b"a"), 0xCA2E9442);
106 assert_eq!(hash_bytes(b"b"), 0x00DB819B);
107 assert_eq!(hash_bytes(b"c"), 0xEEBA5D59);
108 assert_eq!(
109 hash_bytes(b"The quick brown fox jumps over the lazy dog"),
110 0x519E91F5
111 );
112 assert_eq!(
113 hash_bytes(b"The quick brown fox jumps over the lazy dog."),
114 0xAE8EF3CB
115 );
116 }
117}