ferrum_plugin/typemap/
mod.rs

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