any_map/
lib.rs

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
20//
21macro_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        // Ref https://github.com/hyperium/http/blob/v0.2.6/src/extensions.rs#L48-L190
36        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
84//
85define_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}