joaat/
lib.rs

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	/// Create a Joaat hasher with an initial hash.
30	#[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
57/// A builder for default Joaat hashers.
58pub type JoaatBuildHasher = BuildHasherDefault<JoaatHasher>;
59
60/// Hashes bytes from an iterator.
61#[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/// Hashes text converting alphabetical characters to ASCII lowercase.
74#[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/// Hashes a slice of bytes.
81#[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/// A `HashMap` using a default Joaat hasher.
90#[cfg(feature = "std")]
91pub type JoaatHashMap<K, V> = HashMap<K, V, JoaatBuildHasher>;
92
93/// A `HashSet` using a default Joaat hasher.
94#[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}