wasm_cache/
key.rs

1//! Arbitrary cache keys.
2use super::Invalidatable;
3use std::{any::Any, cmp::Ordering, fmt::Debug};
4
5/// Trait for arbitrary cache keys.
6///
7/// Cache keys are arbitrary Rust types that are sortable and comparable.
8pub 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}