ntex_util/services/
extensions.rs1use std::{any::Any, any::TypeId, fmt};
2
3#[derive(Default)]
4pub struct Extensions {
6 map: crate::HashMap<TypeId, Box<dyn Any>>,
7}
8
9impl Extensions {
10 #[inline]
12 pub fn new() -> Extensions {
13 Extensions {
14 map: Default::default(),
15 }
16 }
17
18 pub fn insert<T: 'static>(&mut self, val: T) -> Option<T> {
23 self.map
24 .insert(TypeId::of::<T>(), Box::new(val))
25 .and_then(|item| item.downcast::<T>().map(|boxed| *boxed).ok())
26 }
27
28 pub fn contains<T: 'static>(&self) -> bool {
30 self.map.contains_key(&TypeId::of::<T>())
31 }
32
33 pub fn get<T: 'static>(&self) -> Option<&T> {
35 self.map
36 .get(&TypeId::of::<T>())
37 .and_then(|boxed| boxed.downcast_ref())
38 }
39
40 pub fn get_mut<T: 'static>(&mut self) -> Option<&mut T> {
42 self.map
43 .get_mut(&TypeId::of::<T>())
44 .and_then(|boxed| boxed.downcast_mut())
45 }
46
47 pub fn remove<T: 'static>(&mut self) -> Option<T> {
51 self.map
52 .remove(&TypeId::of::<T>())
53 .and_then(|boxed| boxed.downcast().ok().map(|boxed| *boxed))
54 }
55
56 pub fn extend(&mut self, other: Extensions) {
58 self.map.extend(other.map);
59 }
60
61 #[inline]
62 pub fn is_empty(&self) -> bool {
63 self.map.is_empty()
64 }
65
66 #[inline]
68 pub fn clear(&mut self) {
69 self.map.clear();
70 }
71}
72
73impl fmt::Debug for Extensions {
74 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75 f.debug_struct("Extensions")
76 .field("size", &self.map.len())
77 .finish()
78 }
79}
80
81#[test]
82fn test_debug() {
83 let mut map = Extensions::new();
84 map.insert::<i8>(123);
85 assert_eq!(format!("{map:?}"), "Extensions { size: 1 }");
86}
87
88#[test]
89fn test_remove() {
90 let mut map = Extensions::new();
91
92 map.insert::<i8>(123);
93 assert!(map.get::<i8>().is_some());
94 assert_eq!(map.insert::<i8>(10), Some(123));
95
96 map.remove::<i8>();
97 assert!(map.get::<i8>().is_none());
98}
99
100#[test]
101fn test_clear() {
102 let mut map = Extensions::new();
103
104 map.insert::<i8>(8);
105 map.insert::<i16>(16);
106 map.insert::<i32>(32);
107
108 assert!(map.contains::<i8>());
109 assert!(map.contains::<i16>());
110 assert!(map.contains::<i32>());
111
112 map.clear();
113
114 assert!(!map.contains::<i8>());
115 assert!(!map.contains::<i16>());
116 assert!(!map.contains::<i32>());
117
118 map.insert::<i8>(10);
119 assert_eq!(*map.get::<i8>().unwrap(), 10);
120}
121
122#[test]
123fn test_integers() {
124 let mut map = Extensions::new();
125
126 map.insert::<i8>(8);
127 map.insert::<i16>(16);
128 map.insert::<i32>(32);
129 map.insert::<i64>(64);
130 map.insert::<i128>(128);
131 map.insert::<u8>(8);
132 map.insert::<u16>(16);
133 map.insert::<u32>(32);
134 map.insert::<u64>(64);
135 map.insert::<u128>(128);
136 assert!(map.get::<i8>().is_some());
137 assert!(map.get::<i16>().is_some());
138 assert!(map.get::<i32>().is_some());
139 assert!(map.get::<i64>().is_some());
140 assert!(map.get::<i128>().is_some());
141 assert!(map.get::<u8>().is_some());
142 assert!(map.get::<u16>().is_some());
143 assert!(map.get::<u32>().is_some());
144 assert!(map.get::<u64>().is_some());
145 assert!(map.get::<u128>().is_some());
146}
147
148#[test]
149fn test_composition() {
150 struct Magi<T>(T);
151
152 struct Madoka {
153 god: bool,
154 }
155
156 struct Homura {
157 attempts: usize,
158 }
159
160 struct Mami {
161 guns: usize,
162 }
163
164 let mut map = Extensions::new();
165
166 map.insert(Magi(Madoka { god: false }));
167 map.insert(Magi(Homura { attempts: 0 }));
168 map.insert(Magi(Mami { guns: 999 }));
169
170 assert!(!map.get::<Magi<Madoka>>().unwrap().0.god);
171 assert_eq!(0, map.get::<Magi<Homura>>().unwrap().0.attempts);
172 assert_eq!(999, map.get::<Magi<Mami>>().unwrap().0.guns);
173}
174
175#[test]
176fn test_extensions() {
177 #[derive(Debug, PartialEq)]
178 struct MyType(i32);
179
180 let mut extensions = Extensions::new();
181
182 extensions.insert(5i32);
183 extensions.insert(MyType(10));
184
185 assert_eq!(extensions.get(), Some(&5i32));
186 assert_eq!(extensions.get_mut(), Some(&mut 5i32));
187
188 assert_eq!(extensions.remove::<i32>(), Some(5i32));
189 assert!(extensions.get::<i32>().is_none());
190
191 assert_eq!(extensions.get::<bool>(), None);
192 assert_eq!(extensions.get(), Some(&MyType(10)));
193}
194
195#[test]
196fn test_extend() {
197 #[derive(Debug, PartialEq)]
198 struct MyType(i32);
199
200 let mut extensions2 = Extensions::new();
201 assert!(extensions2.is_empty());
202 extensions2.insert(MyType(10));
203 assert!(!extensions2.is_empty());
204
205 let mut extensions = Extensions::new();
206 extensions.insert(5i32);
207 extensions.extend(extensions2);
208
209 assert_eq!(extensions.get(), Some(&5i32));
210 assert_eq!(extensions.get_mut(), Some(&mut 5i32));
211
212 assert_eq!(extensions.remove::<i32>(), Some(5i32));
213 assert!(extensions.get::<i32>().is_none());
214
215 assert_eq!(extensions.get::<bool>(), None);
216 assert_eq!(extensions.get(), Some(&MyType(10)));
217}