1use std::any::{Any, TypeId};
2use std::collections::HashMap;
3
4pub struct AnyMap(HashMap<TypeId, Box<dyn Any + Send + Sync>>);
10
11impl AnyMap {
12 pub fn new() -> Self {
14 Self(HashMap::new())
15 }
16
17 pub fn insert<T: Any + Send + Sync>(&mut self, val: T) {
19 self.0.insert(TypeId::of::<T>(), Box::new(val));
20 }
21
22 pub fn get<T: Any + Send + Sync>(&self) -> Option<&T> {
24 self.0.get(&TypeId::of::<T>())?.downcast_ref()
25 }
26
27 pub fn remove<T: Any + Send + Sync>(&mut self) -> Option<T> {
29 self.0
30 .remove(&TypeId::of::<T>())
31 .and_then(|b| b.downcast().ok())
32 .map(|b| *b)
33 }
34}
35
36impl Default for AnyMap {
37 fn default() -> Self {
38 Self::new()
39 }
40}
41
42#[cfg(test)]
43mod tests {
44 use super::*;
45
46 #[test]
47 fn insert_get_roundtrip() {
48 let mut m = AnyMap::new();
49 m.insert(42u32);
50 assert_eq!(m.get::<u32>(), Some(&42u32));
51 assert!(m.get::<u64>().is_none());
52 }
53
54 #[test]
55 fn insert_overwrite() {
56 let mut m = AnyMap::new();
57 m.insert(1u32);
58 m.insert(2u32);
59 assert_eq!(m.get::<u32>(), Some(&2u32));
60 }
61
62 #[test]
63 fn remove_takes_value() {
64 let mut m = AnyMap::new();
65 m.insert(99u32);
66 let v = m.remove::<u32>();
67 assert_eq!(v, Some(99u32));
68 assert!(m.get::<u32>().is_none());
69 }
70
71 #[test]
72 fn different_types_coexist() {
73 let mut m = AnyMap::new();
74 m.insert(1u32);
75 m.insert("hello");
76 assert_eq!(m.get::<u32>(), Some(&1u32));
77 assert_eq!(m.get::<&str>(), Some(&"hello"));
78 }
79
80 #[test]
81 fn default_is_empty() {
82 let m = AnyMap::default();
83 assert!(m.get::<u32>().is_none());
84 }
85}