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}