puzz_http/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 Any>, BuildHasherDefault<IdHasher>>;
7
8// 使用`TypeId`作为键时,不需要进行散列。
9#[derive(Default)]
10struct IdHasher(u64);
11
12impl Hasher for IdHasher {
13 fn write(&mut self, _: &[u8]) {
14 unreachable!("TypeId calls write_u64");
15 }
16
17 #[inline]
18 fn write_u64(&mut self, id: u64) {
19 self.0 = id;
20 }
21
22 #[inline]
23 fn finish(&self) -> u64 {
24 self.0
25 }
26}
27
28/// 请求和响应的扩展组件。
29///
30/// 请求和响应可以使用扩展来存储额外的数据。
31#[derive(Default)]
32pub struct Extensions {
33 // 如果从不使用扩展,则无需携带空的`HashMap`,并且这只占用一个字长。
34 map: Option<Box<AnyMap>>,
35}
36
37impl Extensions {
38 /// 创建一个空的扩展。
39 #[inline]
40 pub fn new() -> Self {
41 Self::default()
42 }
43
44 /// 向扩展中插入一个类型。
45 ///
46 /// 如果这种类型已经存在,将替换并返回先前插入的值。
47 ///
48 /// # 例子
49 ///
50 /// ```
51 /// use puzz_http::Extensions;
52 ///
53 /// let mut ext = Extensions::new();
54 ///
55 /// assert!(ext.insert(5i32).is_none());
56 /// assert!(ext.insert(4u8).is_none());
57 /// assert_eq!(ext.insert(9i32), Some(5i32));
58 /// ```
59 pub fn insert<T: 'static>(&mut self, val: T) -> Option<T> {
60 self.map
61 .get_or_insert_with(|| Box::new(HashMap::default()))
62 .insert(TypeId::of::<T>(), Box::new(val))
63 .and_then(|boxed| boxed.downcast().ok().map(|boxed| *boxed))
64 }
65
66 /// 获取先前插入扩展的类型的引用。
67 ///
68 /// # 例子
69 ///
70 /// ```
71 /// use puzz_http::Extensions;
72 ///
73 /// let mut ext = Extensions::new();
74 /// assert!(ext.get::<i32>().is_none());
75 ///
76 /// ext.insert(5i32);
77 /// assert_eq!(ext.get::<i32>(), Some(&5i32));
78 /// ```
79 pub fn get<T: 'static>(&self) -> Option<&T> {
80 self.map
81 .as_ref()
82 .and_then(|map| map.get(&TypeId::of::<T>()))
83 .and_then(|boxed| boxed.downcast_ref())
84 }
85
86 /// 获取先前插入扩展的类型的可变引用。
87 ///
88 /// # 例子
89 ///
90 /// ```
91 /// use puzz_http::Extensions;
92 ///
93 /// let mut ext = Extensions::new();
94 ///
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: '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.downcast_mut())
105 }
106
107 /// 从扩展中删除一个类型。
108 ///
109 /// 如果这种类型存在,将删除并返回此类型。
110 ///
111 /// # 例子
112 ///
113 /// ```
114 /// use puzz_http::Extensions;
115 ///
116 /// let mut ext = Extensions::new();
117 ///
118 /// ext.insert(5i32);
119 ///
120 /// assert_eq!(ext.remove::<i32>(), Some(5i32));
121 /// assert!(ext.get::<i32>().is_none());
122 /// ```
123 pub fn remove<T: 'static>(&mut self) -> Option<T> {
124 self.map
125 .as_mut()
126 .and_then(|map| map.remove(&TypeId::of::<T>()))
127 .and_then(|boxed| boxed.downcast().ok().map(|boxed| *boxed))
128 }
129
130 /// 清空扩展中的所有类型。
131 ///
132 /// # 例子
133 ///
134 /// ```
135 /// use puzz_http::Extensions;
136 ///
137 /// let mut ext = Extensions::new();
138 ///
139 /// ext.insert(5i32);
140 /// ext.clear();
141 ///
142 /// assert!(ext.get::<i32>().is_none());
143 /// ```
144 #[inline]
145 pub fn clear(&mut self) {
146 if let Some(ref mut map) = self.map {
147 map.clear();
148 }
149 }
150
151 /// 检查扩展是否为空。
152 ///
153 /// # 例子
154 ///
155 /// ```
156 /// use puzz_http::Extensions;
157 ///
158 /// let mut ext = Extensions::new();
159 /// assert!(ext.is_empty());
160 ///
161 /// ext.insert(5i32);
162 /// assert!(!ext.is_empty());
163 /// ```
164 #[inline]
165 pub fn is_empty(&self) -> bool {
166 self.map.as_ref().map_or(true, |map| map.is_empty())
167 }
168
169 /// 获取扩展中已插入类型的数量。
170 ///
171 /// # 例子
172 ///
173 /// ```
174 /// use puzz_http::Extensions;
175 ///
176 /// let mut ext = Extensions::new();
177 /// assert_eq!(ext.len(), 0);
178 ///
179 /// ext.insert(5i32);
180 /// assert_eq!(ext.len(), 1);
181 /// ```
182 #[inline]
183 pub fn len(&self) -> usize {
184 self.map.as_ref().map_or(0, |map| map.len())
185 }
186}
187
188impl fmt::Debug for Extensions {
189 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
190 f.debug_struct("Extensions").finish()
191 }
192}