1use core::num::NonZeroU32;
2
3use const_fnv1a_hash::fnv1a_hash_32;
4
5#[derive(Debug, PartialEq, Clone, Copy)]
6#[repr(transparent)]
7pub struct NameHash {
8 hash: NonZeroU32,
9}
10
11impl NameHash {
12 pub const fn new(s: &str) -> Self {
13 let _: () = const {
15 assert!(0 != fnv1a_hash_32(&[], None));
16 };
17
18 let hash32 = fnv1a_hash_32(s.as_bytes(), None);
19 match NonZeroU32::new(hash32) {
20 Some(hash) => Self { hash },
21 None => {
22 let len = if s.len() > 255 { 255 } else { s.len() } as u8;
27 let mut bytes = [len, 0, 0, 0];
28
29 match s.as_bytes() {
31 [] => unreachable!(),
32 [one] => {
33 bytes[1] = *one;
34 bytes[2] = *one;
35 bytes[3] = *one;
36 }
37 [one, two] => {
38 bytes[1] = *one;
39 bytes[2] = *two;
40 bytes[3] = *one;
41 }
42 [one, two, three] => {
43 bytes[1] = *one;
44 bytes[2] = *two;
45 bytes[3] = *three;
46 }
47 [one, two, three, ..] => {
48 bytes[1] = *one;
49 bytes[2] = *two;
50 bytes[3] = *three;
51 }
52 }
53 let val = u32::from_le_bytes(bytes);
54
55 let hash = unsafe { NonZeroU32::new_unchecked(val) };
60 Self { hash }
61 }
62 }
63 }
64
65 pub fn to_u32(&self) -> u32 {
66 self.hash.into()
67 }
68
69 pub fn from_u32(val: u32) -> Option<Self> {
70 let nz = NonZeroU32::new(val)?;
71 Some(Self { hash: nz })
72 }
73}
74
75#[cfg(test)]
76mod test {
77 use crate::nash::NameHash;
78
79 #[test]
80 fn transparent_works() {
81 assert_eq!(size_of::<NameHash>(), 4);
82 assert_eq!(size_of::<Option<NameHash>>(), 4);
83 }
84}