type_store/lib.rs
1//! # type-store
2//!
3//! A generic type map for storing arbitrary data by type.
4
5use std::{
6 any::{Any, TypeId},
7 collections::HashMap,
8 hash::{BuildHasherDefault, Hasher},
9};
10
11/// Optimized hasher for `TypeId`
12/// See https://github.com/chris-morgan/anymap/blob/2e9a570491664eea18ad61d98aa1c557d5e23e67/src/lib.rs#L599
13/// and https://github.com/actix/actix-web/blob/97399e8c8ce584d005577604c10bd391e5da7268/actix-http/src/extensions.rs#L8
14#[derive(Debug, Default)]
15struct TypeIdHasher(u64);
16
17impl Hasher for TypeIdHasher {
18 fn write(&mut self, bytes: &[u8]) {
19 unimplemented!("This TypeIdHasher can only handle u64s, not {:?}", bytes);
20 }
21
22 fn write_u64(&mut self, i: u64) {
23 self.0 = i;
24 }
25
26 fn finish(&self) -> u64 {
27 self.0
28 }
29}
30
31/// A generic type map for storing arbitrary data by type.
32///
33/// # Example
34/// ```rs
35/// use extractors::TypeStore;
36///
37/// let mut store = TypeStore::new();
38/// store.insert(1u32);
39/// store.insert("hello");
40/// assert_eq!(store.get::<u32>(), Some(&1u32));
41/// assert_eq!(store.get::<&str>(), Some(&"hello"));
42/// assert_eq!(store.get::<u64>(), None);
43/// ```
44#[derive(Debug, Default)]
45pub struct TypeStore {
46 map: HashMap<TypeId, Box<dyn Any>, BuildHasherDefault<TypeIdHasher>>,
47}
48
49impl TypeStore {
50 /// Creates an empty `Store`.
51 ///
52 /// # Example
53 /// ```rs
54 /// use extractors::TypeStore;
55 ///
56 /// let store = TypeStore::new();
57 /// assert!(store.is_empty());
58 /// ```
59 #[inline]
60 pub fn new() -> Self {
61 Self {
62 map: HashMap::default(),
63 }
64 }
65
66 /// Insert an item into the map.
67 ///
68 /// If an item of this type was already stored, it will be replaced.
69 ///
70 /// # Example
71 /// ```rs
72 /// use extractors::TypeStore;
73 ///
74 /// let mut store = TypeStore::new();
75 /// store.insert(1u32);
76 /// assert_eq!(store.get::<u32>(), Some(&1u32));
77 /// store.insert(2u32);
78 /// assert_eq!(store.get::<u32>(), Some(&2u32));
79 /// ```
80 #[inline]
81 pub fn insert<T: 'static>(&mut self, val: T) {
82 self.map.insert(TypeId::of::<T>(), Box::new(val));
83 }
84
85 /// Get a reference to an item in the map.
86 /// Returns `None` if the item is not present.
87 ///
88 /// # Example
89 /// ```rs
90 /// use extractors::TypeStore;
91 ///
92 /// let mut store = TypeStore::new();
93 /// store.insert(1u32);
94 /// assert_eq!(store.get::<u32>(), Some(&1u32));
95 /// assert_eq!(store.get::<u64>(), None);
96 /// ```
97 #[inline]
98 pub fn get<T: 'static>(&self) -> Option<&T> {
99 self.map
100 .get(&TypeId::of::<T>())
101 .and_then(|v| v.downcast_ref::<T>())
102 }
103
104 /// Get a mutable reference to an item in the map.
105 /// Returns `None` if the item is not present.
106 ///
107 /// # Example
108 /// ```rs
109 /// use extractors::TypeStore;
110 ///
111 /// let mut store = TypeStore::new();
112 /// store.insert(1u32);
113 /// let val = store.get_mut::<u32>().unwrap();
114 /// *val = 2;
115 /// assert_eq!(store.get::<u32>(), Some(&2u32));
116 /// ```
117 #[inline]
118 pub fn get_mut<T: 'static>(&mut self) -> Option<&mut T> {
119 self.map
120 .get_mut(&TypeId::of::<T>())
121 .and_then(|v| v.downcast_mut::<T>())
122 }
123
124 /// Remove an item from the map.
125 /// Returns `None` if the item is not present, `Some(T)` if it was.
126 ///
127 /// # Example
128 /// ```rs
129 /// use extractors::TypeStore;
130 ///
131 /// let mut store = TypeStore::new();
132 /// store.insert(1u32);
133 /// assert_eq!(store.remove::<u32>(), Some(1u32));
134 /// assert_eq!(store.remove::<u32>(), None);
135 /// ```
136 #[inline]
137 pub fn remove<T: 'static>(&mut self) -> Option<T> {
138 self.map
139 .remove(&TypeId::of::<T>())
140 .and_then(|v| v.downcast::<T>().ok())
141 .map(|v| *v)
142 }
143
144 /// Check if the map contains an item of type `T`.
145 /// Returns `true` if it does, `false` if it doesn't.
146 ///
147 /// # Example
148 /// ```rs
149 /// use extractors::TypeStore;
150 ///
151 /// let mut store = TypeStore::new();
152 /// store.insert(1u32);
153 /// assert!(store.contains::<u32>());
154 /// assert!(!store.contains::<u64>());
155 /// ```
156 #[inline]
157 pub fn contains<T: 'static>(&self) -> bool {
158 self.map.contains_key(&TypeId::of::<T>())
159 }
160
161 /// Clear the map, removing all items.
162 ///
163 /// # Example
164 /// ```rs
165 /// use extractors::TypeStore;
166 ///
167 /// let mut store = TypeStore::new();
168 /// store.insert(1u32);
169 /// store.clear();
170 /// assert!(store.is_empty());
171 /// ```
172 #[inline]
173 pub fn clear(&mut self) {
174 self.map.clear();
175 }
176
177 /// Check if the map is empty.
178 /// Returns `true` if it is, `false` if it isn't.
179 ///
180 /// # Example
181 /// ```rs
182 /// use extractors::TypeStore;
183 ///
184 /// let mut store = TypeStore::new();
185 /// assert!(store.is_empty());
186 /// store.insert(1u32);
187 /// assert!(!store.is_empty());
188 /// ```
189 #[inline]
190 pub fn is_empty(&self) -> bool {
191 self.map.is_empty()
192 }
193}