Skip to content

Commit 2a1611f

Browse files
switch to own TypeMap impl, base on type_map and http
1 parent 8cdfc1c commit 2a1611f

File tree

3 files changed

+121
-4
lines changed

3 files changed

+121
-4
lines changed

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ omnom = "2.1.1"
2626
# features: hyperium/http
2727
http = { version = "0.2.0", optional = true }
2828
anyhow = "1.0.26"
29-
type-map = "0.2.0"
3029

3130
[dev-dependencies]
3231
http = "0.2.0"

src/lib.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ mod method;
121121
mod request;
122122
mod response;
123123
mod status_code;
124+
mod type_map;
124125
mod version;
125126

126127
pub use body::Body;
@@ -152,10 +153,8 @@ pub mod trailers;
152153
#[cfg(feature = "hyperium_http")]
153154
mod hyperium_http;
154155

155-
/// Map type that allows storing any `Sync + Send + 'static` type as local state
156-
/// on a `Request` or `Response`.
157156
#[doc(inline)]
158-
pub use type_map::concurrent::TypeMap;
157+
pub use crate::type_map::TypeMap;
159158

160159
// Not public API. Referenced by macro-generated code.
161160
#[doc(hidden)]

src/type_map.rs

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
use std::any::{Any, TypeId};
2+
use std::collections::HashMap;
3+
use std::fmt;
4+
use std::hash::{BuildHasherDefault, Hasher};
5+
6+
/// Map type that allows storing any `Sync + Send + 'static` type as local state
7+
/// on a `Request` or `Response`.
8+
#[derive(Default)]
9+
pub struct TypeMap {
10+
map: Option<HashMap<TypeId, Box<dyn Any + Send + Sync>, BuildHasherDefault<IdHasher>>>,
11+
}
12+
13+
impl TypeMap {
14+
/// Create an empty `TypeMap`.
15+
#[inline]
16+
pub fn new() -> Self {
17+
Self { map: None }
18+
}
19+
20+
/// Insert a value into this `TypeMap`.
21+
///
22+
/// If a value of this type already exists, it will be returned.
23+
pub fn insert<T: Send + Sync + 'static>(&mut self, val: T) -> Option<T> {
24+
self.map
25+
.get_or_insert_with(|| Default::default())
26+
.insert(TypeId::of::<T>(), Box::new(val))
27+
.and_then(|boxed| (boxed as Box<dyn Any>).downcast().ok().map(|boxed| *boxed))
28+
}
29+
30+
/// Check if container contains value for type
31+
pub fn contains<T: 'static>(&self) -> bool {
32+
self.map
33+
.as_ref()
34+
.and_then(|m| m.get(&TypeId::of::<T>()))
35+
.is_some()
36+
}
37+
38+
/// Get a reference to a value previously inserted on this `TypeMap`.
39+
pub fn get<T: 'static>(&self) -> Option<&T> {
40+
self.map
41+
.as_ref()
42+
.and_then(|m| m.get(&TypeId::of::<T>()))
43+
.and_then(|boxed| (&**boxed as &(dyn Any)).downcast_ref())
44+
}
45+
46+
/// Get a mutable reference to a value previously inserted on this `TypeMap`.
47+
pub fn get_mut<T: 'static>(&mut self) -> Option<&mut T> {
48+
self.map
49+
.as_mut()
50+
.and_then(|m| m.get_mut(&TypeId::of::<T>()))
51+
.and_then(|boxed| (&mut **boxed as &mut (dyn Any)).downcast_mut())
52+
}
53+
54+
/// Remove a value from this `TypeMap`.
55+
///
56+
/// If a value of this type exists, it will be returned.
57+
pub fn remove<T: 'static>(&mut self) -> Option<T> {
58+
self.map
59+
.as_mut()
60+
.and_then(|m| m.remove(&TypeId::of::<T>()))
61+
.and_then(|boxed| (boxed as Box<dyn Any>).downcast().ok().map(|boxed| *boxed))
62+
}
63+
64+
/// Clear the `TypeMap` of all inserted values.
65+
#[inline]
66+
pub fn clear(&mut self) {
67+
self.map = None;
68+
}
69+
}
70+
71+
impl fmt::Debug for TypeMap {
72+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73+
f.debug_struct("TypeMap").finish()
74+
}
75+
}
76+
77+
// With TypeIds as keys, there's no need to hash them. So we simply use an identy hasher.
78+
#[derive(Default)]
79+
struct IdHasher(u64);
80+
81+
impl Hasher for IdHasher {
82+
fn write(&mut self, _: &[u8]) {
83+
unreachable!("TypeId calls write_u64");
84+
}
85+
86+
#[inline]
87+
fn write_u64(&mut self, id: u64) {
88+
self.0 = id;
89+
}
90+
91+
#[inline]
92+
fn finish(&self) -> u64 {
93+
self.0
94+
}
95+
}
96+
97+
#[cfg(test)]
98+
mod tests {
99+
use super::*;
100+
#[test]
101+
fn test_type_map() {
102+
#[derive(Debug, PartialEq)]
103+
struct MyType(i32);
104+
105+
let mut map = TypeMap::new();
106+
107+
map.insert(5i32);
108+
map.insert(MyType(10));
109+
110+
assert_eq!(map.get(), Some(&5i32));
111+
assert_eq!(map.get_mut(), Some(&mut 5i32));
112+
113+
assert_eq!(map.remove::<i32>(), Some(5i32));
114+
assert!(map.get::<i32>().is_none());
115+
116+
assert_eq!(map.get::<bool>(), None);
117+
assert_eq!(map.get(), Some(&MyType(10)));
118+
}
119+
}

0 commit comments

Comments
 (0)