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