1use core::{
2 any::{Any, TypeId},
3 hash::BuildHasherDefault,
4 ops::Deref,
5};
6use std::collections::HashMap;
7
8#[cfg(feature = "cloneable-any")]
9use cloneable_any::CloneableAny;
10
11pub mod extensions;
12pub mod hasher;
13
14#[cfg(feature = "cloneable-any")]
15pub use extensions::{CloneableExtensions, CloneableExtensionsSync};
16pub use extensions::{Extensions, ExtensionsSync};
17
18use self::hasher::Hasher;
19
20macro_rules! define_any_map {
22 ($(#[$attr:meta])* $name:ident, $any_or_cloneable_any_trait:tt $(+ $send_sync_trait_and_others:tt)*, $static_lifetime:tt $(+ $clone_trait_and_others:tt)*) => {
23 $(#[$attr])*
24 #[derive(Default, Debug)]
25 pub struct $name(HashMap<TypeId, Box<dyn $any_or_cloneable_any_trait $(+ $send_sync_trait_and_others)*>, BuildHasherDefault<Hasher>>);
26
27 impl Deref for $name {
28 type Target = HashMap<TypeId, Box<dyn $any_or_cloneable_any_trait $(+ $send_sync_trait_and_others)*>, BuildHasherDefault<Hasher>>;
29
30 fn deref(&self) -> &Self::Target {
31 &self.0
32 }
33 }
34
35 impl $name {
37 pub fn new() -> Self {
38 Self::default()
39 }
40
41 pub fn with_capacity(capacity: usize) -> Self {
42 Self(HashMap::with_capacity_and_hasher(capacity, Default::default()))
43 }
44
45 pub fn insert<T: $static_lifetime $(+ $clone_trait_and_others)* $(+ $send_sync_trait_and_others)*>(&mut self, val: T) -> Option<T> {
46 self.0
47 .insert(TypeId::of::<T>(), Box::new(val))
48 .and_then(|boxed| {
49 (boxed as Box<dyn $any_or_cloneable_any_trait>)
50 .downcast()
51 .ok()
52 .map(|boxed| *boxed)
53 })
54 }
55
56 pub fn get<T: $static_lifetime $(+ $clone_trait_and_others)*>(&self) -> Option<&T> {
57 self.0
58 .get(&TypeId::of::<T>())
59 .and_then(|boxed| (&**boxed as &(dyn $any_or_cloneable_any_trait)).downcast_ref())
60 }
61
62 pub fn get_mut<T: $static_lifetime $(+ $clone_trait_and_others)*>(&mut self) -> Option<&mut T> {
63 self.0
64 .get_mut(&TypeId::of::<T>())
65 .and_then(|boxed| (&mut **boxed as &mut (dyn $any_or_cloneable_any_trait)).downcast_mut())
66 }
67
68 pub fn remove<T: $static_lifetime $(+ $clone_trait_and_others)*>(&mut self) -> Option<T> {
69 self.0.remove(&TypeId::of::<T>()).and_then(|boxed| {
70 (boxed as Box<dyn $any_or_cloneable_any_trait>)
71 .downcast()
72 .ok()
73 .map(|boxed| *boxed)
74 })
75 }
76
77 pub fn contains<T: $static_lifetime $(+ $clone_trait_and_others)*>(&self) -> bool {
78 self.0.contains_key(&TypeId::of::<T>())
79 }
80 }
81 }
82}
83
84define_any_map!(AnyMap, Any, 'static);
86
87define_any_map!(AnyMapSync, Any + Send + Sync, 'static);
88
89#[cfg(feature = "cloneable-any")]
90define_any_map!(
91 #[derive(Clone)]
92 CloneableAnyMap,
93 CloneableAny,
94 'static + Clone
95);
96
97#[cfg(feature = "cloneable-any")]
98define_any_map!(
99 #[derive(Clone)]
100 CloneableAnyMapSync,
101 CloneableAny + Send + Sync,
102 'static + Clone
103);
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108
109 #[derive(Debug, PartialEq)]
110 struct Foo(usize);
111
112 #[derive(Clone)]
113 struct Bar(usize);
114
115 #[test]
116 fn test_any_map() {
117 let mut map = AnyMap::default();
118
119 assert!(!map.contains::<Foo>());
120
121 assert!(map.insert(Foo(1)).is_none());
122
123 assert!(map.contains::<Foo>());
124 assert_eq!(map.len(), 1);
125
126 assert_eq!(map.get::<Foo>().unwrap(), &Foo(1));
127 map.get_mut::<Foo>().map(|x| {
128 x.0 = 2;
129 x
130 });
131 assert_eq!(map.get::<Foo>().unwrap(), &Foo(2));
132 assert!(map.remove::<Foo>().is_some());
133
134 assert!(!map.contains::<Foo>());
135 assert_eq!(map.len(), 0);
136
137 println!("{:?}", map);
138 }
139
140 #[test]
141 fn test_any_map_sync() {
142 let mut map = AnyMapSync::new();
143
144 assert!(map.insert(Foo(1)).is_none());
145
146 assert!(map.contains::<Foo>());
147 assert_eq!(map.len(), 1);
148
149 println!("{:?}", map);
150 }
151
152 #[cfg(feature = "cloneable-any")]
153 #[test]
154 fn test_cloneable_any_map() {
155 #[derive(Debug, Clone)]
156 struct Wrapper(CloneableAnyMap);
157
158 let mut map = CloneableAnyMap::with_capacity(1);
159
160 assert!(map.insert(Bar(1)).is_none());
161
162 assert!(map.contains::<Bar>());
163 assert_eq!(map.len(), 1);
164
165 println!("{:?}", map);
166
167 let wrapper = Wrapper(map);
168 #[allow(clippy::redundant_clone)]
169 let _ = wrapper.clone();
170 }
171
172 #[cfg(feature = "cloneable-any")]
173 #[test]
174 fn test_cloneable_any_map_sync() {
175 #[derive(Debug, Clone)]
176 struct Wrapper(CloneableAnyMapSync);
177
178 let mut map = CloneableAnyMapSync::new();
179
180 assert!(map.insert(Bar(1)).is_none());
181
182 assert!(map.contains::<Bar>());
183 assert_eq!(map.len(), 1);
184
185 println!("{:?}", map);
186
187 let wrapper = Wrapper(map);
188 #[allow(clippy::redundant_clone)]
189 let _ = wrapper.clone();
190 }
191}