typemap/
lib.rs

1#![deny(missing_docs, warnings)]
2
3//! A type-based key value store where one value type is allowed for each key.
4
5extern crate unsafe_any as uany;
6
7use uany::{UnsafeAny, UnsafeAnyExt};
8use std::any::{Any, TypeId};
9use std::collections::{hash_map, HashMap};
10use std::marker::PhantomData;
11
12use Entry::{Occupied, Vacant};
13
14pub use internals::{CloneAny, DebugAny};
15use internals::Implements;
16
17/// A map keyed by types.
18///
19/// Can contain one value of any type for each key type, as defined
20/// by the Assoc trait.
21///
22/// You usually do not need to worry about the A type parameter, but it
23/// can be used to add bounds to the possible value types that can
24/// be stored in this map. Usually, you are looking for `ShareMap`, which
25/// is `Send + Sync`.
26#[derive(Default, Debug)]
27pub struct TypeMap<A: ?Sized = UnsafeAny>
28where A: UnsafeAnyExt {
29    data: HashMap<TypeId, Box<A>>
30}
31
32impl<A: ?Sized> Clone for TypeMap<A>
33where A: UnsafeAnyExt, Box<A>: Clone { // We are a bit cleverer than derive.
34    fn clone(&self) -> TypeMap<A> {
35        TypeMap { data: self.data.clone() }
36    }
37}
38
39/// A version of `TypeMap` containing only `Send` types.
40pub type SendMap = TypeMap<UnsafeAny + Send>;
41
42/// A version of `TypeMap` containing only `Sync` types.
43pub type SyncMap = TypeMap<UnsafeAny + Sync>;
44
45/// A version of `TypeMap` containing only `Send + Sync` types.
46pub type ShareMap = TypeMap<UnsafeAny + Send + Sync>;
47
48/// A version of `TypeMap` containing only `Clone` types.
49pub type CloneMap = TypeMap<CloneAny>;
50
51/// A version of `TypeMap` containing only `Clone + Send + Sync` types.
52pub type ShareCloneMap = TypeMap<CloneAny + Send + Sync>;
53
54/// A version of `TypeMap` containing only `Debug` types.
55pub type DebugMap = TypeMap<DebugAny>;
56
57/// A version of `TypeMap` containing only `Debug + Send + Sync` types.
58pub type ShareDebugMap = TypeMap<DebugAny + Send + Sync>;
59
60// Assert some properties on SyncMap, SendMap and ShareMap.
61fn _assert_types() {
62    use std::fmt::Debug;
63
64    fn _assert_send<T: Send>() { }
65    fn _assert_sync<T: Sync>() { }
66    fn _assert_clone<T: Clone>() { }
67    fn _assert_debug<T: Debug>() { }
68
69    _assert_send::<SendMap>();
70    _assert_sync::<SyncMap>();
71    _assert_send::<ShareMap>();
72    _assert_sync::<ShareMap>();
73    _assert_clone::<CloneMap>();
74    _assert_debug::<DebugMap>();
75}
76
77/// This trait defines the relationship between keys and values in a TypeMap.
78///
79/// It is implemented for Keys, with a phantom associated type for the values.
80pub trait Key: Any {
81    /// The value type associated with this key type.
82    type Value: Any;
83}
84
85impl TypeMap {
86    /// Create a new, empty TypeMap.
87    pub fn new() -> TypeMap {
88        TypeMap::custom()
89    }
90}
91
92impl<A: UnsafeAnyExt + ?Sized> TypeMap<A> {
93    /// Create a new, empty TypeMap.
94    ///
95    /// Can be used with any `A` parameter; `new` is specialized to get around
96    /// the required type annotations when using this function.
97    pub fn custom() -> TypeMap<A> {
98        TypeMap {
99            data: HashMap::new()
100        }
101    }
102
103    /// Insert a value into the map with a specified key type.
104    pub fn insert<K: Key>(&mut self, val: K::Value) -> Option<K::Value>
105    where K::Value: Any + Implements<A> {
106        self.data.insert(TypeId::of::<K>(), val.into_object()).map(|v| unsafe {
107            *v.downcast_unchecked::<K::Value>()
108        })
109    }
110
111    /// Find a value in the map and get a reference to it.
112    pub fn get<K: Key>(&self) -> Option<&K::Value>
113    where K::Value: Any + Implements<A> {
114        self.data.get(&TypeId::of::<K>()).map(|v| unsafe {
115            v.downcast_ref_unchecked::<K::Value>()
116        })
117    }
118
119    /// Find a value in the map and get a mutable reference to it.
120    pub fn get_mut<K: Key>(&mut self) -> Option<&mut K::Value>
121    where K::Value: Any + Implements<A> {
122        self.data.get_mut(&TypeId::of::<K>()).map(|v| unsafe {
123            v.downcast_mut_unchecked::<K::Value>()
124        })
125    }
126
127    /// Check if a key has an associated value stored in the map.
128    pub fn contains<K: Key>(&self) -> bool {
129        self.data.contains_key(&TypeId::of::<K>())
130    }
131
132    /// Remove a value from the map.
133    ///
134    /// Returns `true` if a value was removed.
135    pub fn remove<K: Key>(&mut self) -> Option<K::Value>
136    where K::Value: Any + Implements<A> {
137        self.data.remove(&TypeId::of::<K>()).map(|v| unsafe {
138            *v.downcast_unchecked::<K::Value>()
139        })
140    }
141
142    /// Get the given key's corresponding entry in the map for in-place manipulation.
143    pub fn entry<'a, K: Key>(&'a mut self) -> Entry<'a, K, A>
144    where K::Value: Any + Implements<A> {
145        match self.data.entry(TypeId::of::<K>()) {
146            hash_map::Entry::Occupied(e) => Occupied(OccupiedEntry { data: e, _marker: PhantomData }),
147            hash_map::Entry::Vacant(e) => Vacant(VacantEntry { data: e, _marker: PhantomData })
148        }
149    }
150
151    /// Read the underlying HashMap
152    pub unsafe fn data(&self) -> &HashMap<TypeId, Box<A>> {
153        &self.data
154    }
155
156    /// Get a mutable reference to the underlying HashMap
157    pub unsafe fn data_mut(&mut self) -> &mut HashMap<TypeId, Box<A>> {
158        &mut self.data
159    }
160
161    /// Get the number of values stored in the map.
162    pub fn len(&self) -> usize {
163        self.data.len()
164    }
165
166    /// Return true if the map contains no values.
167    pub fn is_empty(&self) -> bool {
168        self.data.is_empty()
169    }
170
171    /// Remove all entries from the map.
172    pub fn clear(&mut self) {
173        self.data.clear()
174    }
175}
176
177/// A view onto an entry in a TypeMap.
178pub enum Entry<'a, K, A: ?Sized + UnsafeAnyExt + 'a = UnsafeAny> {
179    /// A view onto an occupied entry in a TypeMap.
180    Occupied(OccupiedEntry<'a, K, A>),
181    /// A view onto an unoccupied entry in a TypeMap.
182    Vacant(VacantEntry<'a, K, A>)
183}
184
185impl<'a, K: Key, A: ?Sized + UnsafeAnyExt + 'a = UnsafeAny> Entry<'a, K, A> {
186    /// Ensures a value is in the entry by inserting the default if empty, and returns
187    /// a mutable reference to the value in the entry.
188    pub fn or_insert(self, default: K::Value) -> &'a mut K::Value
189    where K::Value: Any + Implements<A> {
190        match self {
191            Entry::Occupied(inner) => inner.into_mut(),
192            Entry::Vacant(inner) => inner.insert(default),
193        }
194    }
195
196    /// Ensures a value is in the entry by inserting the result of the default function if empty,
197    /// and returns a mutable reference to the value in the entry.
198    pub fn or_insert_with<F: FnOnce() -> K::Value>(self, default: F) -> &'a mut K::Value
199    where K::Value: Any + Implements<A> {
200        match self {
201            Entry::Occupied(inner) => inner.into_mut(),
202            Entry::Vacant(inner) => inner.insert(default()),
203        }
204    }
205}
206
207/// A view onto an occupied entry in a TypeMap.
208pub struct OccupiedEntry<'a, K, A: ?Sized + UnsafeAnyExt + 'a = UnsafeAny> {
209    data: hash_map::OccupiedEntry<'a, TypeId, Box<A>>,
210    _marker: PhantomData<K>
211}
212
213/// A view onto an unoccupied entry in a TypeMap.
214pub struct VacantEntry<'a, K, A: ?Sized + UnsafeAnyExt + 'a = UnsafeAny> {
215    data: hash_map::VacantEntry<'a, TypeId, Box<A>>,
216    _marker: PhantomData<K>
217}
218
219impl<'a, K: Key, A: UnsafeAnyExt + ?Sized> OccupiedEntry<'a, K, A> {
220    /// Get a reference to the entry's value.
221    pub fn get(&self) -> &K::Value
222    where K::Value: Any + Implements<A> {
223        unsafe {
224            self.data.get().downcast_ref_unchecked()
225        }
226    }
227
228    /// Get a mutable reference to the entry's value.
229    pub fn get_mut(&mut self) -> &mut K::Value
230    where K::Value: Any + Implements<A> {
231        unsafe {
232            self.data.get_mut().downcast_mut_unchecked()
233        }
234    }
235
236    /// Transform the entry into a mutable reference with the same lifetime as the map.
237    pub fn into_mut(self) -> &'a mut K::Value
238    where K::Value: Any + Implements<A> {
239        unsafe {
240            self.data.into_mut().downcast_mut_unchecked()
241        }
242    }
243
244    /// Set the entry's value and return the previous value.
245    pub fn insert(&mut self, value: K::Value) -> K::Value
246    where K::Value: Any + Implements<A> {
247        unsafe {
248            *self.data.insert(value.into_object()).downcast_unchecked()
249        }
250    }
251
252    /// Move the entry's value out of the map, consuming the entry.
253    pub fn remove(self) -> K::Value
254    where K::Value: Any + Implements<A> {
255        unsafe {
256            *self.data.remove().downcast_unchecked()
257        }
258    }
259}
260
261impl<'a, K: Key, A: ?Sized + UnsafeAnyExt> VacantEntry<'a, K, A> {
262    /// Set the entry's value and return a mutable reference to it.
263    pub fn insert(self, value: K::Value) -> &'a mut K::Value
264    where K::Value: Any + Implements<A> {
265        unsafe {
266            self.data.insert(value.into_object()).downcast_mut_unchecked()
267        }
268    }
269}
270
271mod internals;
272
273#[cfg(test)]
274mod test {
275    use super::{TypeMap, CloneMap, DebugMap, SendMap, Key};
276    use super::Entry::{Occupied, Vacant};
277
278    #[derive(Debug, PartialEq)]
279    struct KeyType;
280
281    #[derive(Clone, Debug, PartialEq)]
282    struct Value(u8);
283
284    impl Key for KeyType { type Value = Value; }
285
286    #[test] fn test_pairing() {
287        let mut map = TypeMap::new();
288        map.insert::<KeyType>(Value(100));
289        assert_eq!(*map.get::<KeyType>().unwrap(), Value(100));
290        assert!(map.contains::<KeyType>());
291    }
292
293    #[test] fn test_remove() {
294        let mut map = TypeMap::new();
295        map.insert::<KeyType>(Value(10));
296        assert!(map.contains::<KeyType>());
297        map.remove::<KeyType>();
298        assert!(!map.contains::<KeyType>());
299    }
300
301    #[test] fn test_entry() {
302        let mut map = TypeMap::new();
303        map.insert::<KeyType>(Value(20));
304        match map.entry::<KeyType>() {
305            Occupied(e) => {
306                assert_eq!(e.get(), &Value(20));
307                assert_eq!(e.remove(), Value(20));
308            },
309            _ => panic!("Unable to locate inserted item.")
310        }
311        assert!(!map.contains::<KeyType>());
312        match map.entry::<KeyType>() {
313            Vacant(e) => {
314                e.insert(Value(2));
315            },
316            _ => panic!("Found non-existant entry.")
317        }
318        assert!(map.contains::<KeyType>());
319    }
320
321    #[test] fn test_entry_or_insert() {
322        let mut map = TypeMap::new();
323        map.entry::<KeyType>().or_insert(Value(20)).0 += 1;
324        assert_eq!(map.get::<KeyType>().unwrap(), &Value(21));
325
326        // on existing value
327        map.entry::<KeyType>().or_insert(Value(100)).0 += 1;
328        assert_eq!(map.get::<KeyType>().unwrap(), &Value(22));
329    }
330
331    #[test] fn test_custom_bounds() {
332        let mut map: SendMap = TypeMap::custom();
333        map.insert::<KeyType>(Value(10));
334        assert!(map.contains::<KeyType>());
335        map.remove::<KeyType>();
336        assert!(!map.contains::<KeyType>());
337    }
338
339    #[test] fn test_clonemap() {
340        let mut map: CloneMap = TypeMap::custom();
341        map.insert::<KeyType>(Value(10));
342        assert!(map.contains::<KeyType>());
343        let cloned = map.clone();
344        assert_eq!(map.get::<KeyType>(), cloned.get::<KeyType>());
345    }
346
347    #[test] fn test_debugmap() {
348        let mut map: DebugMap = TypeMap::custom();
349        map.insert::<KeyType>(Value(10));
350        assert!(map.contains::<KeyType>());
351    }
352}