any_map/
extensions.rs

1use crate::{AnyMap, AnyMapSync};
2#[cfg(feature = "cloneable-any")]
3use crate::{CloneableAnyMap, CloneableAnyMapSync};
4
5macro_rules! define_extensions {
6    ($(#[$attr:meta])* $name:ident, $any_map_struct:tt, $any_or_cloneable_any_trait:tt $(+ $send_sync_trait_and_others:tt)*, $static_lifetime:tt $(+ $clone_trait_and_others:tt)*) => {
7        $(#[$attr])*
8        #[derive(Default, Debug)]
9        pub struct $name(Option<Box<$any_map_struct>>);
10
11        // Ref https://github.com/hyperium/http/blob/v0.2.6/src/extensions.rs#L48-L190
12        impl $name {
13            pub fn new() -> Self {
14                Self::default()
15            }
16
17            pub fn with_capacity(capacity: usize) -> Self {
18                Self(Some(Box::new($any_map_struct::with_capacity(capacity))))
19            }
20
21            pub fn insert<T: $static_lifetime $(+ $clone_trait_and_others)* $(+ $send_sync_trait_and_others)*>(&mut self, val: T) -> Option<T> {
22                self.0
23                    .get_or_insert_with(|| Box::new($any_map_struct::default())).insert(val)
24            }
25
26            pub fn get<T: $static_lifetime $(+ $clone_trait_and_others)*>(&self) -> Option<&T> {
27                self.0
28                    .as_ref()
29                    .and_then(|x| x.get::<T>())
30            }
31
32            pub fn get_mut<T: $static_lifetime $(+ $clone_trait_and_others)*>(&mut self) -> Option<&mut T> {
33                self.0
34                    .as_mut()
35                    .and_then(|x| x.get_mut::<T>())
36            }
37
38            pub fn remove<T: $static_lifetime $(+ $clone_trait_and_others)*>(&mut self) -> Option<T> {
39                self.0
40                    .as_mut()
41                    .and_then(|x| x.remove::<T>())
42            }
43
44            pub fn contains<T: $static_lifetime $(+ $clone_trait_and_others)*>(&self) -> bool {
45                self.0
46                    .as_ref()
47                    .and_then(|x| Some(x.contains::<T>())) == Some(true)
48            }
49        }
50
51        impl $name {
52            pub fn get_inner(&self) -> Option<&Box<$any_map_struct>> {
53                self.0
54                    .as_ref()
55            }
56        }
57    }
58}
59
60//
61define_extensions!(Extensions, AnyMap, Any, 'static);
62
63define_extensions!(
64    ExtensionsSync,
65    AnyMapSync, Any + Send + Sync, 'static
66);
67
68#[cfg(feature = "cloneable-any")]
69define_extensions!(
70    #[derive(Clone)]
71    CloneableExtensions,
72    CloneableAnyMap,
73    CloneableAny,
74    'static + Clone
75);
76
77#[cfg(feature = "cloneable-any")]
78define_extensions!(
79    #[derive(Clone)]
80    CloneableExtensionsSync,
81    CloneableAnyMapSync,
82    CloneableAny + Send + Sync,
83    'static + Clone
84);
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89
90    #[derive(Debug, PartialEq)]
91    struct Foo(usize);
92
93    #[derive(Clone)]
94    struct Bar(usize);
95
96    #[test]
97    fn test_extensions() {
98        let mut extensions = Extensions::default();
99
100        assert!(!extensions.contains::<Foo>());
101
102        assert!(extensions.insert(Foo(1)).is_none());
103
104        assert!(extensions.contains::<Foo>());
105        assert_eq!(extensions.get_inner().map(|x| x.len()), Some(1));
106
107        assert_eq!(extensions.get::<Foo>().unwrap(), &Foo(1));
108        extensions.get_mut::<Foo>().map(|x| {
109            x.0 = 2;
110            x
111        });
112        assert_eq!(extensions.get::<Foo>().unwrap(), &Foo(2));
113        assert!(extensions.remove::<Foo>().is_some());
114
115        assert!(!extensions.contains::<Foo>());
116        assert_eq!(extensions.get_inner().map(|x| x.len()), Some(0));
117
118        println!("{:?}", extensions);
119    }
120
121    #[test]
122    fn test_extensions_sync() {
123        let mut extensions = ExtensionsSync::new();
124
125        assert!(extensions.insert(Foo(1)).is_none());
126
127        assert!(extensions.contains::<Foo>());
128        assert_eq!(extensions.get_inner().map(|x| x.len()), Some(1));
129
130        println!("{:?}", extensions);
131    }
132
133    #[cfg(feature = "cloneable-any")]
134    #[test]
135    fn test_cloneable_extensions() {
136        #[derive(Debug, Clone)]
137        struct Wrapper(CloneableExtensions);
138
139        let mut extensions = CloneableExtensions::with_capacity(1);
140
141        assert!(extensions.insert(Bar(1)).is_none());
142
143        assert!(extensions.contains::<Bar>());
144        assert_eq!(extensions.get_inner().map(|x| x.len()), Some(1));
145
146        println!("{:?}", extensions);
147
148        let wrapper = Wrapper(extensions);
149        #[allow(clippy::redundant_clone)]
150        let _ = wrapper.clone();
151    }
152
153    #[cfg(feature = "cloneable-any")]
154    #[test]
155    fn test_cloneable_extensions_sync() {
156        #[derive(Debug, Clone)]
157        struct Wrapper(CloneableExtensionsSync);
158
159        let mut extensions = CloneableExtensionsSync::new();
160
161        assert!(extensions.insert(Bar(1)).is_none());
162
163        assert!(extensions.contains::<Bar>());
164        assert_eq!(extensions.get_inner().map(|x| x.len()), Some(1));
165
166        println!("{:?}", extensions);
167
168        let wrapper = Wrapper(extensions);
169        #[allow(clippy::redundant_clone)]
170        let _ = wrapper.clone();
171    }
172}