http_with_url/
extensions.rs

1use std::any::{Any, TypeId};
2use std::collections::HashMap;
3use std::hash::BuildHasherDefault;
4use std::fmt;
5
6use fnv::FnvHasher;
7
8type AnyMap = HashMap<TypeId, Box<Any + Send + Sync>, BuildHasherDefault<FnvHasher>>;
9
10/// A type map of protocol extensions.
11///
12/// `Extensions` can be used by `Request` and `Response` to store
13/// extra data derived from the underlying protocol.
14#[derive(Default)]
15pub struct Extensions {
16    map: AnyMap,
17}
18
19impl Extensions {
20    /// Create an empty `Extensions`.
21    #[inline]
22    pub fn new() -> Extensions {
23        Extensions {
24            map: HashMap::default(),
25        }
26    }
27
28    /// Insert a type into this `Extensions`.
29    ///
30    /// If a extension of this type already existed, it will
31    /// be returned.
32    ///
33    /// # Example
34    ///
35    /// ```
36    /// # use http::Extensions;
37    /// let mut ext = Extensions::new();
38    /// assert!(ext.insert(5i32).is_none());
39    /// assert!(ext.insert(4u8).is_none());
40    /// assert_eq!(ext.insert(9i32), Some(5i32));
41    /// ```
42    pub fn insert<T: Send + Sync + 'static>(&mut self, val: T) -> Option<T> {
43        self.map.insert(TypeId::of::<T>(), Box::new(val))
44            .and_then(|boxed| {
45                //TODO: we can use unsafe and remove double checking the type id
46                (boxed as Box<Any + 'static>)
47                    .downcast()
48                    .ok()
49                    .map(|boxed| *boxed)
50            })
51    }
52
53    /// Get a reference to a type previously inserted on this `Extensions`.
54    ///
55    /// # Example
56    ///
57    /// ```
58    /// # use http::Extensions;
59    /// let mut ext = Extensions::new();
60    /// assert!(ext.get::<i32>().is_none());
61    /// ext.insert(5i32);
62    ///
63    /// assert_eq!(ext.get::<i32>(), Some(&5i32));
64    /// ```
65    pub fn get<T: Send + Sync + 'static>(&self) -> Option<&T> {
66        self.map.get(&TypeId::of::<T>())
67            //TODO: we can use unsafe and remove double checking the type id
68            .and_then(|boxed| (&**boxed as &(Any + 'static)).downcast_ref())
69    }
70
71    /// Get a mutable reference to a type previously inserted on this `Extensions`.
72    ///
73    /// # Example
74    ///
75    /// ```
76    /// # use http::Extensions;
77    /// let mut ext = Extensions::new();
78    /// ext.insert(String::from("Hello"));
79    /// ext.get_mut::<String>().unwrap().push_str(" World");
80    ///
81    /// assert_eq!(ext.get::<String>().unwrap(), "Hello World");
82    /// ```
83    pub fn get_mut<T: Send + Sync + 'static>(&mut self) -> Option<&mut T> {
84        self.map.get_mut(&TypeId::of::<T>())
85            //TODO: we can use unsafe and remove double checking the type id
86            .and_then(|boxed| (&mut **boxed as &mut (Any + 'static)).downcast_mut())
87    }
88
89
90    /// Remove a type from this `Extensions`.
91    ///
92    /// If a extension of this type existed, it will be returned.
93    ///
94    /// # Example
95    ///
96    /// ```
97    /// # use http::Extensions;
98    /// let mut ext = Extensions::new();
99    /// ext.insert(5i32);
100    /// assert_eq!(ext.remove::<i32>(), Some(5i32));
101    /// assert!(ext.get::<i32>().is_none());
102    /// ```
103    pub fn remove<T: Send + Sync + 'static>(&mut self) -> Option<T> {
104        self.map.remove(&TypeId::of::<T>())
105            .and_then(|boxed| {
106                //TODO: we can use unsafe and remove double checking the type id
107                (boxed as Box<Any + 'static>)
108                    .downcast()
109                    .ok()
110                    .map(|boxed| *boxed)
111            })
112    }
113
114    /// Clear the `Extensions` of all inserted extensions.
115    ///
116    /// # Example
117    ///
118    /// ```
119    /// # use http::Extensions;
120    /// let mut ext = Extensions::new();
121    /// ext.insert(5i32);
122    /// ext.clear();
123    ///
124    /// assert!(ext.get::<i32>().is_none());
125    /// ```
126    #[inline]
127    pub fn clear(&mut self) {
128        self.map.clear();
129    }
130}
131
132impl fmt::Debug for Extensions {
133    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
134        f.debug_struct("Extensions")
135            .finish()
136    }
137}
138
139#[test]
140fn test_extensions() {
141    #[derive(Debug, PartialEq)]
142    struct MyType(i32);
143
144    let mut extensions = Extensions::new();
145
146    extensions.insert(5i32);
147    extensions.insert(MyType(10));
148
149    assert_eq!(extensions.get(), Some(&5i32));
150    assert_eq!(extensions.get_mut(), Some(&mut 5i32));
151
152    assert_eq!(extensions.remove::<i32>(), Some(5i32));
153    assert!(extensions.get::<i32>().is_none());
154
155    assert_eq!(extensions.get::<bool>(), None);
156    assert_eq!(extensions.get(), Some(&MyType(10)));
157}