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}