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