1pub fn short_hash(text: &str) -> String {
5 let (mut h1, mut h2): (u32, u32) = (0xdead_beef, 0x41c6_ce57);
6 for unit in text.encode_utf16() {
7 let unit = u32::from(unit);
8 h1 = (h1 ^ unit).wrapping_mul(2_654_435_761);
9 h2 = (h2 ^ unit).wrapping_mul(1_597_334_677);
10 }
11 h1 = (h1 ^ (h1 >> 16)).wrapping_mul(2_246_822_507)
12 ^ (h2 ^ (h2 >> 13)).wrapping_mul(3_266_489_909);
13 h2 = (h2 ^ (h2 >> 16)).wrapping_mul(2_246_822_507)
14 ^ (h1 ^ (h1 >> 13)).wrapping_mul(3_266_489_909);
15 format!("{}{}", base36(h2), base36(h1))
16}
17
18fn base36(mut value: u32) -> String {
19 if value == 0 {
20 return "0".into();
21 }
22 let mut digits = Vec::new();
23 while value > 0 {
24 digits.push(std::char::from_digit(value % 36, 36).unwrap_or('0'));
25 value /= 36;
26 }
27 digits.iter().rev().collect()
28}
29
30#[cfg(test)]
31mod tests {
32 use super::*;
33
34 #[test]
35 fn hashes_like_pi() {
36 assert_eq!(short_hash(""), "k4n83c7h0j2b");
38 assert_eq!(
39 short_hash("call_abc|fc_0123456789abcdefghijklmnopqrstuvwxyz"),
40 "zdt65wxpmvl8"
41 );
42 }
43}