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 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
60define_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}