1use std::any;
12use std::cmp::Ordering;
13use std::hash::Hash;
14use std::hash::Hasher;
15use std::ops::Deref;
16
17#[derive(Clone, Eq, PartialEq, Debug)]
19pub struct Key {
20 hash: u64,
21 s: &'static str,
22}
23
24impl PartialOrd for Key {
25 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
26 Some(self.cmp(other))
27 }
28}
29
30impl Ord for Key {
31 fn cmp(&self, other: &Self) -> Ordering {
32 self.s.cmp(other.s)
33 }
34}
35
36#[allow(clippy::derived_hash_with_manual_eq)]
37impl Hash for Key {
38 fn hash<H: Hasher>(&self, state: &mut H) {
39 self.hash.hash(state);
40 }
41}
42
43impl Deref for Key {
44 type Target = str;
45
46 fn deref(&self) -> &str {
47 self.s
48 }
49}
50
51impl Key {
52 const fn hash(s: &str) -> u64 {
54 let mut hash = 0xcbf29ce484222325;
55 let mut i = 0;
56 while i < s.len() {
57 let b = s.as_bytes()[i];
58 hash ^= b as u64;
59 hash = hash.wrapping_mul(0x100000001b3);
60 i += 1;
61 }
62 hash
63 }
64
65 pub const fn new(s: &'static str) -> Key {
67 let hash = Self::hash(s);
68 Key::new_unchecked(hash, s)
69 }
70
71 pub const fn new_unchecked(hash: u64, s: &'static str) -> Key {
72 Key { hash, s }
73 }
74
75 pub fn for_type_name<T: ?Sized>() -> Key {
76 #[cfg(rust_nightly)]
78 return Key {
79 hash: AllocativeKeyForType::<T>::KEY.hash,
80 s: AllocativeKeyForType::<T>::KEY.s,
81 };
82 #[cfg(not(rust_nightly))]
84 return Key::new(any::type_name::<T>());
85 }
86}
87
88#[cfg(rust_nightly)]
89struct AllocativeKeyForType<T: ?Sized>(std::marker::PhantomData<fn(&T)>);
90
91#[cfg(rust_nightly)]
92impl<T: ?Sized> AllocativeKeyForType<T> {
93 pub const KEY: Key = Key::new(any::type_name::<T>());
95}