1use super::Invalidatable;
3use std::{any::Any, cmp::Ordering, fmt::Debug};
4
5pub trait CacheKey<M = ()>: Debug + Invalidatable<M> + 'static {
9 fn any(&self) -> &(dyn Any + 'static);
10 fn any_eq(&self, other: &dyn Any) -> bool;
11 fn any_ord(&self, other: &dyn Any) -> Ordering;
12 fn clone_boxed(&self) -> Box<dyn CacheKey<M>>;
13}
14
15impl<M: 'static> PartialOrd<Self> for dyn CacheKey<M> {
16 fn partial_cmp(&self, other: &dyn CacheKey<M>) -> Option<Ordering> {
17 Some(self.any_ord(other.any()))
18 }
19}
20
21impl<M: 'static> PartialEq<Self> for dyn CacheKey<M> {
22 fn eq(&self, other: &dyn CacheKey<M>) -> bool {
23 self.any_eq(other.any())
24 }
25}
26
27impl<M: 'static> Eq for dyn CacheKey<M> {}
28
29impl<M: 'static> Ord for dyn CacheKey<M> {
30 fn cmp(&self, other: &dyn CacheKey<M>) -> Ordering {
31 self.any_ord(other.any())
32 }
33}
34
35impl<M: 'static> Clone for Box<dyn CacheKey<M>> {
36 fn clone(&self) -> Self {
37 ((&**self) as &dyn CacheKey<M>).clone_boxed()
38 }
39}
40
41impl<M, T: Debug + Eq + Ord + Any + Clone + Invalidatable<M> + 'static> CacheKey<M> for T {
42 fn any_eq(&self, other: &dyn Any) -> bool {
43 match other.downcast_ref::<T>() {
44 Some(other) => {
45 println!("Using eq: {}", std::any::type_name::<T>());
46 self.eq(other)
47 }
48 None => false,
49 }
50 }
51
52 fn any_ord(&self, other: &dyn Any) -> Ordering {
53 match self.type_id().cmp(&other.type_id()) {
54 Ordering::Equal => match <dyn Any>::downcast_ref::<T>(other) {
55 Some(other) => self.cmp(other),
56 None => unreachable!(),
57 },
58 ordering => ordering,
59 }
60 }
61
62 fn any(&self) -> &(dyn Any + 'static) {
63 self as &(dyn Any + 'static)
64 }
65
66 fn clone_boxed(&self) -> Box<dyn CacheKey<M>> {
67 Box::new(self.clone())
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74 use std::collections::BTreeMap;
75
76 impl Invalidatable<()> for String {}
77 impl Invalidatable<()> for Vec<usize> {}
78
79 #[test]
80 fn cache_item_eq_identity() {
81 let string: Box<dyn CacheKey> = Box::new(String::from("Hello"));
82 assert!(&string == &string);
83 }
84
85 #[test]
86 fn cache_item_eq_equal() {
87 println!("Running test");
88 let string1: Box<dyn CacheKey> = Box::new(String::from("Hello"));
89 let string2: Box<dyn CacheKey> = Box::new(String::from("Hello"));
90 assert!(&string1 == &string2);
91 assert!(string1 == string2);
92 }
93
94 #[test]
95 fn cache_item_new_different() {
96 let string_hello: Box<dyn CacheKey> = Box::new(String::from("Hello"));
97 let string_world: Box<dyn CacheKey> = Box::new(String::from("World"));
98 assert_eq!(string_hello.any_eq(&string_world), false);
99 assert!(string_hello != string_world);
100 }
101
102 #[test]
103 fn cache_item_different_type() {
104 let string_hello: Box<dyn CacheKey> = Box::new(String::from("Hello"));
105 let array_empty: Box<dyn CacheKey> = Box::new(Vec::<usize>::new());
106 assert_eq!(string_hello.any_eq(&array_empty), false);
107 }
108
109 #[test]
110 fn test_cache_key() {
111 let mut map: BTreeMap<Box<dyn CacheKey>, &str> = Default::default();
112 map.insert(Box::new(String::from("Hello")), "String Hello");
113 map.insert(Box::new(String::from("World")), "String World");
114 }
115}