Skip to main content

nylon_ring_host/
extensions.rs

1use std::any::{Any, TypeId};
2use std::collections::HashMap;
3use std::fmt;
4use std::hash::{BuildHasherDefault, Hasher};
5
6type AnyMap = HashMap<TypeId, Box<dyn AnyClone + Send + Sync>, BuildHasherDefault<IdHasher>>;
7
8// With TypeIds as keys, there's no need to hash them. They are already hashes
9// themselves, coming from the compiler. The IdHasher just holds the u64 of
10// the TypeId, and then returns it, instead of doing any bit fiddling.
11#[derive(Default)]
12struct IdHasher(u64);
13
14impl Hasher for IdHasher {
15    fn write(&mut self, _: &[u8]) {
16        unreachable!("TypeId calls write_u64");
17    }
18
19    #[inline]
20    fn write_u64(&mut self, id: u64) {
21        self.0 = id;
22    }
23
24    #[inline]
25    fn finish(&self) -> u64 {
26        self.0
27    }
28}
29
30/// A type map of protocol extensions.
31///
32/// `Extensions` can be used by `HighLevelRequest` to store
33/// extra data derived from the underlying protocol.
34#[derive(Clone, Default)]
35pub struct Extensions {
36    // If extensions are never used, no need to carry around an empty HashMap.
37    // That's 3 words. Instead, this is only 1 word.
38    map: Option<Box<AnyMap>>,
39}
40
41impl Extensions {
42    /// Create an empty `Extensions`.
43    #[inline]
44    pub fn new() -> Extensions {
45        Extensions { map: None }
46    }
47
48    /// Insert a type into this `Extensions`.
49    ///
50    /// If a extension of this type already existed, it will
51    /// be returned and replaced with the new one.
52    ///
53    /// # Example
54    ///
55    /// ```
56    /// # use nylon_ring_host::Extensions;
57    /// let mut ext = Extensions::new();
58    /// assert!(ext.insert(5i32).is_none());
59    /// assert!(ext.insert(4u8).is_none());
60    /// assert_eq!(ext.insert(9i32), Some(5i32));
61    /// ```
62    pub fn insert<T: Clone + Send + Sync + 'static>(&mut self, val: T) -> Option<T> {
63        self.map
64            .get_or_insert_with(Box::default)
65            .insert(TypeId::of::<T>(), Box::new(val))
66            .and_then(|boxed| boxed.into_any().downcast().ok().map(|boxed| *boxed))
67    }
68
69    /// Get a reference to a type previously inserted on this `Extensions`.
70    ///
71    /// # Example
72    ///
73    /// ```
74    /// # use nylon_ring_host::Extensions;
75    /// let mut ext = Extensions::new();
76    /// assert!(ext.get::<i32>().is_none());
77    /// ext.insert(5i32);
78    ///
79    /// assert_eq!(ext.get::<i32>(), Some(&5i32));
80    /// ```
81    pub fn get<T: Send + Sync + 'static>(&self) -> Option<&T> {
82        self.map
83            .as_ref()
84            .and_then(|map| map.get(&TypeId::of::<T>()))
85            .and_then(|boxed| (**boxed).as_any().downcast_ref())
86    }
87
88    /// Get a mutable reference to a type previously inserted on this `Extensions`.
89    ///
90    /// # Example
91    ///
92    /// ```
93    /// # use nylon_ring_host::Extensions;
94    /// let mut ext = Extensions::new();
95    /// ext.insert(String::from("Hello"));
96    /// ext.get_mut::<String>().unwrap().push_str(" World");
97    ///
98    /// assert_eq!(ext.get::<String>().unwrap(), "Hello World");
99    /// ```
100    pub fn get_mut<T: Send + Sync + 'static>(&mut self) -> Option<&mut T> {
101        self.map
102            .as_mut()
103            .and_then(|map| map.get_mut(&TypeId::of::<T>()))
104            .and_then(|boxed| (**boxed).as_any_mut().downcast_mut())
105    }
106
107    /// Get a mutable reference to a type, inserting `value` if not already present on this
108    /// `Extensions`.
109    ///
110    /// # Example
111    ///
112    /// ```
113    /// # use nylon_ring_host::Extensions;
114    /// let mut ext = Extensions::new();
115    /// *ext.get_or_insert(1i32) += 2;
116    ///
117    /// assert_eq!(*ext.get::<i32>().unwrap(), 3);
118    /// ```
119    pub fn get_or_insert<T: Clone + Send + Sync + 'static>(&mut self, value: T) -> &mut T {
120        self.get_or_insert_with(|| value)
121    }
122
123    /// Get a mutable reference to a type, inserting the value created by `f` if not already present
124    /// on this `Extensions`.
125    ///
126    /// # Example
127    ///
128    /// ```
129    /// # use nylon_ring_host::Extensions;
130    /// let mut ext = Extensions::new();
131    /// *ext.get_or_insert_with(|| 1i32) += 2;
132    ///
133    /// assert_eq!(*ext.get::<i32>().unwrap(), 3);
134    /// ```
135    pub fn get_or_insert_with<T: Clone + Send + Sync + 'static, F: FnOnce() -> T>(
136        &mut self,
137        f: F,
138    ) -> &mut T {
139        let out = self
140            .map
141            .get_or_insert_with(Box::default)
142            .entry(TypeId::of::<T>())
143            .or_insert_with(|| Box::new(f()));
144
145        // Safety: TypeId::of::<T>() guarantees this entry contains type T,
146        // so the downcast cannot fail. Using expect instead of unwrap for clarity.
147        (**out)
148            .as_any_mut()
149            .downcast_mut()
150            .expect("TypeId mismatch: this is a bug in Extensions implementation")
151    }
152
153    /// Get a mutable reference to a type, inserting the type's default value if not already present
154    /// on this `Extensions`.
155    ///
156    /// # Example
157    ///
158    /// ```
159    /// # use nylon_ring_host::Extensions;
160    /// let mut ext = Extensions::new();
161    /// *ext.get_or_insert_default::<i32>() += 2;
162    ///
163    /// assert_eq!(*ext.get::<i32>().unwrap(), 2);
164    /// ```
165    pub fn get_or_insert_default<T: Default + Clone + Send + Sync + 'static>(&mut self) -> &mut T {
166        self.get_or_insert_with(T::default)
167    }
168
169    /// Remove a type from this `Extensions`.
170    ///
171    /// If a extension of this type existed, it will be returned.
172    ///
173    /// # Example
174    ///
175    /// ```
176    /// # use nylon_ring_host::Extensions;
177    /// let mut ext = Extensions::new();
178    /// ext.insert(5i32);
179    /// assert_eq!(ext.remove::<i32>(), Some(5i32));
180    /// assert!(ext.get::<i32>().is_none());
181    /// ```
182    pub fn remove<T: Send + Sync + 'static>(&mut self) -> Option<T> {
183        self.map
184            .as_mut()
185            .and_then(|map| map.remove(&TypeId::of::<T>()))
186            .and_then(|boxed| boxed.into_any().downcast().ok().map(|boxed| *boxed))
187    }
188
189    /// Clear the `Extensions` of all inserted extensions.
190    ///
191    /// # Example
192    ///
193    /// ```
194    /// # use nylon_ring_host::Extensions;
195    /// let mut ext = Extensions::new();
196    /// ext.insert(5i32);
197    /// ext.clear();
198    ///
199    /// assert!(ext.get::<i32>().is_none());
200    /// ```
201    #[inline]
202    pub fn clear(&mut self) {
203        if let Some(ref mut map) = self.map {
204            map.clear();
205        }
206    }
207
208    /// Check whether the extension set is empty or not.
209    ///
210    /// # Example
211    ///
212    /// ```
213    /// # use nylon_ring_host::Extensions;
214    /// let mut ext = Extensions::new();
215    /// assert!(ext.is_empty());
216    /// ext.insert(5i32);
217    /// assert!(!ext.is_empty());
218    /// ```
219    #[inline]
220    pub fn is_empty(&self) -> bool {
221        self.map.as_ref().is_none_or(|map| map.is_empty())
222    }
223
224    /// Get the number of extensions available.
225    ///
226    /// # Example
227    ///
228    /// ```
229    /// # use nylon_ring_host::Extensions;
230    /// let mut ext = Extensions::new();
231    /// assert_eq!(ext.len(), 0);
232    /// ext.insert(5i32);
233    /// assert_eq!(ext.len(), 1);
234    /// ```
235    #[inline]
236    pub fn len(&self) -> usize {
237        self.map.as_ref().map_or(0, |map| map.len())
238    }
239
240    /// Extends `self` with another `Extensions`.
241    ///
242    /// If an instance of a specific type exists in both, the one in `self` is overwritten with the
243    /// one from `other`.
244    ///
245    /// # Example
246    ///
247    /// ```
248    /// # use nylon_ring_host::Extensions;
249    /// let mut ext_a = Extensions::new();
250    /// ext_a.insert(8u8);
251    /// ext_a.insert(16u16);
252    ///
253    /// let mut ext_b = Extensions::new();
254    /// ext_b.insert(4u8);
255    /// ext_b.insert("hello");
256    ///
257    /// ext_a.extend(ext_b);
258    /// assert_eq!(ext_a.len(), 3);
259    /// assert_eq!(ext_a.get::<u8>(), Some(&4u8));
260    /// assert_eq!(ext_a.get::<u16>(), Some(&16u16));
261    /// assert_eq!(ext_a.get::<&'static str>().copied(), Some("hello"));
262    /// ```
263    pub fn extend(&mut self, other: Self) {
264        if let Some(other) = other.map {
265            if let Some(map) = &mut self.map {
266                map.extend(*other);
267            } else {
268                self.map = Some(other);
269            }
270        }
271    }
272}
273
274impl fmt::Debug for Extensions {
275    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
276        f.debug_struct("Extensions").finish()
277    }
278}
279
280trait AnyClone: Any {
281    fn clone_box(&self) -> Box<dyn AnyClone + Send + Sync>;
282    fn as_any(&self) -> &dyn Any;
283    fn as_any_mut(&mut self) -> &mut dyn Any;
284    fn into_any(self: Box<Self>) -> Box<dyn Any>;
285}
286
287impl<T: Clone + Send + Sync + 'static> AnyClone for T {
288    fn clone_box(&self) -> Box<dyn AnyClone + Send + Sync> {
289        Box::new(self.clone())
290    }
291
292    fn as_any(&self) -> &dyn Any {
293        self
294    }
295
296    fn as_any_mut(&mut self) -> &mut dyn Any {
297        self
298    }
299
300    fn into_any(self: Box<Self>) -> Box<dyn Any> {
301        self
302    }
303}
304
305impl Clone for Box<dyn AnyClone + Send + Sync> {
306    fn clone(&self) -> Self {
307        (**self).clone_box()
308    }
309}
310
311#[cfg(test)]
312mod tests {
313    use super::Extensions;
314
315    #[test]
316    fn test_extensions() {
317        #[derive(Clone, Debug, PartialEq)]
318        struct MyType(i32);
319
320        let mut extensions = Extensions::new();
321
322        extensions.insert(5i32);
323        extensions.insert(MyType(10));
324
325        assert_eq!(extensions.get(), Some(&5i32));
326        assert_eq!(extensions.get_mut(), Some(&mut 5i32));
327
328        let ext2 = extensions.clone();
329
330        assert_eq!(extensions.remove::<i32>(), Some(5i32));
331        assert!(extensions.get::<i32>().is_none());
332
333        // clone still has it
334        assert_eq!(ext2.get(), Some(&5i32));
335        assert_eq!(ext2.get(), Some(&MyType(10)));
336
337        assert_eq!(extensions.get::<bool>(), None);
338        assert_eq!(extensions.get(), Some(&MyType(10)));
339    }
340}