ntex_util/services/
extensions.rs

1use std::{any::Any, any::TypeId, fmt};
2
3#[derive(Default)]
4/// A type map of request extensions.
5pub struct Extensions {
6    map: crate::HashMap<TypeId, Box<dyn Any>>,
7}
8
9impl Extensions {
10    /// Create an empty `Extensions`.
11    #[inline]
12    pub fn new() -> Extensions {
13        Extensions {
14            map: Default::default(),
15        }
16    }
17
18    /// Insert a type into this `Extensions`.
19    ///
20    /// If a extension of this type already existed, it will
21    /// be returned.
22    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    /// Check if container contains entry
29    pub fn contains<T: 'static>(&self) -> bool {
30        self.map.contains_key(&TypeId::of::<T>())
31    }
32
33    /// Get a reference to a type previously inserted on this `Extensions`.
34    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    /// Get a mutable reference to a type previously inserted on this `Extensions`.
41    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    /// Remove a type from this `Extensions`.
48    ///
49    /// If a extension of this type existed, it will be returned.
50    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    /// Add all items from other `Extensions`
57    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    /// Clear the `Extensions` of all inserted extensions.
67    #[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}