1use std::cmp::PartialEq;
2use std::fmt::Debug;
3use std::hash::{Hash, Hasher};
4use std::rc::Rc;
5
6#[derive(Clone, Debug)]
11pub struct Key(Rc<dyn machinery::Keyable>);
12
13impl Key {
14 pub fn new<T>(value: T) -> Key
19 where
20 T: machinery::Keyable + 'static,
21 {
22 Key(Rc::new(value))
23 }
24}
25
26impl<T> From<Rc<T>> for Key
27where
28 T: machinery::Keyable + 'static,
29{
30 fn from(value: Rc<T>) -> Self {
31 Key(value)
32 }
33}
34
35impl PartialEq for Key {
36 fn eq(&self, other: &Key) -> bool {
37 self.0.eq(other.0.as_any())
38 }
39}
40
41impl Eq for Key {}
42
43impl Hash for Key {
44 fn hash<H>(&self, state: &mut H)
45 where
46 H: Hasher,
47 {
48 self.0.hash(state)
49 }
50}
51
52mod machinery {
53 use std::any::Any;
54 use std::cmp::PartialEq;
55 use std::fmt::Debug;
56 use std::hash::{Hash, Hasher};
57
58 pub trait Keyable: Any + Debug {
59 fn eq(&self, other: &dyn Any) -> bool;
60 fn as_any(&self) -> &dyn Any;
61 fn hash(&self, state: &mut dyn Hasher);
62 }
63
64 impl<T> Keyable for T
65 where
66 T: Debug + Eq + Hash + 'static,
67 {
68 fn eq(&self, other: &dyn Any) -> bool {
69 match other.downcast_ref::<Self>() {
70 Some(other) => PartialEq::eq(self, other),
71 _ => false,
72 }
73 }
74
75 fn as_any(&self) -> &dyn Any {
76 self
77 }
78
79 fn hash(&self, mut state: &mut dyn Hasher) {
80 T::hash(self, &mut state)
81 }
82 }
83}
84
85#[cfg(test)]
86mod tests {
87 use super::Key;
88
89 #[test]
90 fn test_key() {
91 assert_eq!(Key::new((1, "Hello")), Key::new((1, "Hello")));
92 assert_ne!(Key::new((1, "Hello")), Key::new((2, "Hello")));
93 }
94}