lang_extension/any/
key.rs

1use std::collections::hash_map::DefaultHasher;
2use std::hash::{Hash, Hasher};
3
4use super::*;
5
6pub trait KeyConstraint: ValueConstraint + Eq + Hash {}
7
8impl<T: ?Sized + ValueConstraint + Eq + Hash> KeyConstraint for T {}
9
10pub trait Key: Value {
11    fn hashcode(&self) -> u64 {
12        self.memory_address() as u64
13    }
14
15    as_trait!(Key);
16    as_boxed!(Key);
17}
18
19impl<T: ?Sized + KeyConstraint> Key for T {
20    fn hashcode(&self) -> u64 {
21        let mut hasher = DefaultHasher::default();
22        self.hash(&mut hasher);
23        hasher.finish()
24    }
25
26    as_trait!(impl Key);
27    as_boxed!(impl Key);
28}
29
30#[macro_export]
31macro_rules! boxed_key_trait {
32    ($trait:tt) => {
33as_boxed!(impl Eq for $trait);
34as_boxed!(impl Hash for $trait);
35boxed_value_trait!($trait);
36    };
37
38    ($trait:tt<$($param:tt), *>) => {
39as_boxed!(impl Eq for $trait<$($param), *>);
40as_boxed!(impl Hash for $trait<$($param), *>);
41boxed_value_trait!($trait<$($param), *>);
42    };
43
44    ($trait:tt<$($param:tt: $constraint0:tt $(+ $constraint:tt)*), *>) => {
45as_boxed!(impl Eq for $trait<$($param: $constraint0 $(+ $constraint)*), *>);
46as_boxed!(impl Hash for $trait<$($param: $constraint0 $(+ $constraint)*), *>);
47boxed_value_trait!($trait<$($param: $constraint0 $(+ $constraint)*), *>);
48    };
49
50    ($trait:tt<$($param:tt: ?Sized + $constraint0:tt $(+ $constraint:tt)*), *>) => {
51as_boxed!(impl Eq for $trait<$($param: ?Sized + $constraint0 $(+ $constraint)*), *>);
52as_boxed!(impl Hash for $trait<$($param: ?Sized + $constraint0 $(+ $constraint)*), *>);
53boxed_value_trait!($trait<$($param: ?Sized + $constraint0 $(+ $constraint)*), *>);
54    };
55
56    ($trait:tt<$($param:tt: 'static + $constraint0:tt $(+ $constraint:tt)*), *>) => {
57as_boxed!(impl Eq for $trait<$($param: 'static + $constraint0 $(+ $constraint)*), *>);
58as_boxed!(impl Hash for $trait<$($param: 'static + $constraint0 $(+ $constraint)*), *>);
59boxed_value_trait!($trait<$($param: 'static + $constraint0 $(+ $constraint)*), *>);
60    };
61
62    ($trait:tt<$($param:tt: 'static + ?Sized + $constraint0:tt $(+ $constraint:tt)*), *>) => {
63as_boxed!(impl Eq for $trait<$($param: 'static + ?Sized + $constraint0 $(+ $constraint)*), *>);
64as_boxed!(impl Hash for $trait<$($param: 'static + ?Sized + $constraint0 $(+ $constraint)*), *>);
65boxed_value_trait!($trait<$($param: 'static + ?Sized + $constraint0 $(+ $constraint)*), *>);
66    };
67}
68
69boxed_key_trait!(Key);
70
71#[allow(dead_code)]
72#[cfg(test)]
73mod tests {
74
75    use super::*;
76    use crate::*;
77    use std::collections::HashMap;
78    use std::fmt::Debug;
79
80    trait K1<K: KeyConstraint>: Key {
81        fn say(&self, _k: K) {}
82
83        as_boxed!(K1<K>);
84    }
85
86    #[derive(Hash, PartialEq, Eq, Debug, Clone)]
87    struct S1 {
88        a: i32,
89        b: u32,
90    }
91
92    impl<K: KeyConstraint> K1<K> for S1 {
93        as_boxed!(impl K1<K>);
94    }
95
96    boxed_key_trait!(K1<K: KeyConstraint>);
97
98    #[test]
99    fn hashcode() {
100        let s = S1 { a: 1, b: 2 };
101        assert_eq!(s.hashcode(), s.clone().hashcode());
102
103        let bs: Box<dyn Key> = Box::new(s);
104        assert_eq!(bs.hashcode(), bs.clone().hashcode());
105
106        let mut hasher = DefaultHasher::new();
107        bs.hash(&mut hasher);
108        let _ = hasher.finish();
109    }
110
111    #[test]
112    fn hashmap() {
113        let k = S1 { a: 1, b: 2 };
114        let v = S1 { a: 11, b: 22 };
115        let key: Box<dyn Key> = Box::new(k.clone());
116        let value: Box<dyn Value> = Box::new(v.clone());
117        let mut map = HashMap::<Box<dyn Key>, Box<dyn Value>>::new();
118        map.insert(key.clone(), value.clone());
119        assert_eq!(&value, map.get(&key).unwrap());
120    }
121
122    trait SomeType0<K: KeyConstraint, V: ValueConstraint>: Key {
123        fn say(&self, k: K, v: V);
124
125        as_boxed!(SomeType0<K, V>);
126        as_trait!(SomeType0<K, V>);
127    }
128
129    boxed_key_trait!(SomeType0<K: KeyConstraint, V: ValueConstraint>);
130
131    trait SomeType1<K: KeyConstraint + Debug, V: ValueConstraint>: Key {
132        fn say(&self, k: K, v: V);
133
134        as_boxed!(SomeType1<K, V>);
135        as_trait!(SomeType1<K, V>);
136    }
137
138    boxed_key_trait!(SomeType1<K: KeyConstraint + Debug, V: ValueConstraint>);
139
140    trait SomeType2<K: ?Sized + KeyConstraint, V: ?Sized + ValueConstraint>: Key {
141        fn say(&self, k: K, v: V);
142
143        as_boxed!(SomeType2<K, V>);
144        as_trait!(SomeType2<K, V>);
145    }
146
147    boxed_key_trait!(SomeType2<K: ?Sized + KeyConstraint, V: ?Sized + ValueConstraint>);
148
149    trait SomeType3<K: 'static + KeyConstraint, V: 'static + ValueConstraint>: Key {
150        fn say(&self, k: K, v: V);
151
152        as_boxed!(SomeType3<K, V>);
153        as_trait!(SomeType3<K, V>);
154    }
155
156    boxed_key_trait!(SomeType3<K: 'static + KeyConstraint, V: 'static + ValueConstraint>);
157
158    trait SomeType4<K: 'static + ?Sized + KeyConstraint, V: 'static + ?Sized + ValueConstraint>:
159        Key
160    {
161        fn say(&self, k: K, v: V);
162
163        as_boxed!(SomeType4<K, V>);
164        as_trait!(SomeType4<K, V>);
165    }
166
167    boxed_key_trait!(SomeType4<K: 'static + ?Sized + KeyConstraint, V: 'static + ?Sized + ValueConstraint>);
168}