1use std::{
2 any::{Any, TypeId},
3 collections::HashMap,
4};
5
6#[derive(Default)]
8pub struct Storage {
9 inner: HashMap<TypeId, Box<dyn Any + Send>>,
10}
11
12impl Storage {
13 #[must_use]
15 pub fn new() -> Self {
16 Self::default()
17 }
18
19 #[allow(clippy::missing_panics_doc)]
22 #[must_use]
23 pub fn get<T>(&self) -> Option<&T>
24 where
25 T: Any + Send,
26 {
27 self.inner.get(&TypeId::of::<T>()).map(|val| {
28 let any_debug_ref: &(dyn Any + Send) = &**val;
29 any_debug_ref.downcast_ref::<T>().unwrap()
30 })
31 }
32
33 #[allow(clippy::missing_panics_doc)]
36 #[must_use]
37 pub fn get_mut<T>(&mut self) -> Option<&mut T>
38 where
39 T: Any + Send,
40 {
41 self.inner.get_mut(&TypeId::of::<T>()).map(|val| {
42 let any_debug_ref: &mut (dyn Any + Send) = &mut **val;
43 any_debug_ref.downcast_mut::<T>().unwrap()
44 })
45 }
46
47 #[allow(clippy::missing_panics_doc)]
50 pub fn insert<T>(&mut self, val: T) -> Option<T>
51 where
52 T: Any + Send,
53 {
54 self.inner
55 .insert(TypeId::of::<T>(), Box::new(val))
56 .map(|val: Box<dyn Any + Send>| *val.downcast::<T>().unwrap())
57 }
58
59 #[allow(clippy::missing_panics_doc)]
62 pub fn remove<T>(&mut self) -> Option<T>
63 where
64 T: Any + Send,
65 {
66 self.inner
67 .remove(&TypeId::of::<T>())
68 .map(|val: Box<dyn Any + Send>| *val.downcast::<T>().unwrap())
69 }
70}
71
72#[test]
73fn works() {
74 #[derive(Debug)]
75 #[allow(dead_code)]
76 struct MyVal(String);
77
78 let mut s = Storage::new();
79 s.insert(MyVal("test".into()));
80 let v = s.get::<MyVal>();
82 assert!(v.is_some());
83 assert_eq!(v.unwrap().0, "test".to_string());
84
85 let v = s.get_mut::<MyVal>();
86 assert!(v.is_some());
87 assert_eq!(v.as_ref().unwrap().0, "test".to_string());
88 *v.unwrap() = MyVal("hmm".into());
89
90 let v = s.insert(MyVal("jop".into()));
91 assert!(v.is_some());
92 assert_eq!(v.unwrap().0, "hmm".to_string());
93
94 let v = s.remove::<MyVal>();
95 assert!(v.is_some());
96 assert_eq!(v.unwrap().0, "jop".to_string());
97}