043578f158cde1cf059048033f7efcc737bdab72
[anymap] / src / lib.rs
1 //! This crate provides the `AnyMap` type, a safe and convenient store for one value of each type.
2
3 #![feature(default_type_params)]
4 #![warn(unused_qualifications, non_upper_case_globals,
5 variant_size_differences, unused_typecasts,
6 missing_docs, unused_results)]
7
8 #[cfg(test)]
9 extern crate test;
10
11 use std::any::Any;
12 use std::intrinsics::{forget, TypeId};
13 use std::collections::HashMap;
14 use std::collections::hash_map;
15 use std::hash::{Hash, Hasher, Writer};
16 use std::mem::{transmute, transmute_copy};
17 use std::raw::TraitObject;
18
19 pub use Entry::{Vacant, Occupied};
20
21 struct TypeIdHasher;
22
23 struct TypeIdState {
24 value: u64,
25 }
26
27 impl Writer for TypeIdState {
28 #[inline(always)]
29 fn write(&mut self, bytes: &[u8]) {
30 // This expects to receive one and exactly one 64-bit value
31 debug_assert!(bytes.len() == 8);
32 unsafe {
33 std::ptr::copy_nonoverlapping_memory(&mut self.value,
34 transmute(&bytes[0]),
35 1)
36 }
37 }
38 }
39
40 impl Hasher<TypeIdState> for TypeIdHasher {
41 fn hash<Sized? T: Hash<TypeIdState>>(&self, value: &T) -> u64 {
42 let mut state = TypeIdState {
43 value: 0,
44 };
45 value.hash(&mut state);
46 state.value
47 }
48 }
49
50 /// An extension of `AnyRefExt` allowing unchecked downcasting of trait objects to `&T`.
51 trait UncheckedAnyRefExt<'a> {
52 /// Returns a reference to the boxed value, assuming that it is of type `T`. This should only be
53 /// called if you are ABSOLUTELY CERTAIN of `T` as you will get really wacky output if it’s not.
54 unsafe fn downcast_ref_unchecked<T: 'static>(self) -> &'a T;
55 }
56
57 impl<'a> UncheckedAnyRefExt<'a> for &'a (Any + 'a) {
58 #[inline]
59 unsafe fn downcast_ref_unchecked<T: 'static>(self) -> &'a T {
60 // Get the raw representation of the trait object
61 let to: TraitObject = transmute_copy(&self);
62
63 // Extract the data pointer
64 transmute(to.data)
65 }
66 }
67
68 /// An extension of `AnyMutRefExt` allowing unchecked downcasting of trait objects to `&mut T`.
69 trait UncheckedAnyMutRefExt<'a> {
70 /// Returns a reference to the boxed value, assuming that it is of type `T`. This should only be
71 /// called if you are ABSOLUTELY CERTAIN of `T` as you will get really wacky output if it’s not.
72 unsafe fn downcast_mut_unchecked<T: 'static>(self) -> &'a mut T;
73 }
74
75 impl<'a> UncheckedAnyMutRefExt<'a> for &'a mut (Any + 'a) {
76 #[inline]
77 unsafe fn downcast_mut_unchecked<T: 'static>(self) -> &'a mut T {
78 // Get the raw representation of the trait object
79 let to: TraitObject = transmute_copy(&self);
80
81 // Extract the data pointer
82 transmute(to.data)
83 }
84 }
85
86 /// An extension of `BoxAny` allowing unchecked downcasting of trait objects to `Box<T>`.
87 trait UncheckedBoxAny {
88 /// Returns the boxed value, assuming that it is of type `T`. This should only be called if you
89 /// are ABSOLUTELY CERTAIN of `T` as you will get really wacky output if it’s not.
90 unsafe fn downcast_unchecked<T: 'static>(self) -> Box<T>;
91 }
92
93 impl UncheckedBoxAny for Box<Any + 'static> {
94 #[inline]
95 unsafe fn downcast_unchecked<T: 'static>(self) -> Box<T> {
96 // Get the raw representation of the trait object
97 let to: TraitObject = *transmute::<&Box<Any>, &TraitObject>(&self);
98
99 // Prevent destructor on self being run
100 forget(self);
101
102 // Extract the data pointer
103 transmute(to.data)
104 }
105 }
106
107 /// A map containing zero or one values for any given type and allowing convenient,
108 /// type-safe access to those values.
109 ///
110 /// ```rust
111 /// # use anymap::AnyMap;
112 /// let mut data = AnyMap::new();
113 /// assert_eq!(data.get(), None::<&int>);
114 /// data.insert(42i);
115 /// assert_eq!(data.get(), Some(&42i));
116 /// data.remove::<int>();
117 /// assert_eq!(data.get::<int>(), None);
118 ///
119 /// #[deriving(PartialEq, Show)]
120 /// struct Foo {
121 /// str: String,
122 /// }
123 ///
124 /// assert_eq!(data.get::<Foo>(), None);
125 /// data.insert(Foo { str: "foo".to_string() });
126 /// assert_eq!(data.get(), Some(&Foo { str: "foo".to_string() }));
127 /// data.get_mut::<Foo>().map(|foo| foo.str.push('t'));
128 /// assert_eq!(data.get::<Foo>().unwrap().str.as_slice(), "foot");
129 /// ```
130 ///
131 /// Values containing non-static references are not permitted.
132 pub struct AnyMap {
133 data: HashMap<TypeId, Box<Any + 'static>, TypeIdHasher>,
134 }
135
136 impl AnyMap {
137 /// Construct a new `AnyMap`.
138 pub fn new() -> AnyMap {
139 AnyMap {
140 data: HashMap::with_hasher(TypeIdHasher),
141 }
142 }
143 }
144
145 impl AnyMap {
146 /// Deprecated: Renamed to `get`.
147 #[deprecated = "Renamed to `get`"]
148 pub fn find<T: Any + 'static>(&self) -> Option<&T> {
149 self.get::<T>()
150 }
151
152 /// Deprecated: Renamed to `get_mut`.
153 #[deprecated = "Renamed to `get_mut`"]
154 pub fn find_mut<T: Any + 'static>(&mut self) -> Option<&mut T> {
155 self.get_mut::<T>()
156 }
157
158 /// Retrieve the value stored in the map for the type `T`, if it exists.
159 pub fn get<T: Any + 'static>(&self) -> Option<&T> {
160 self.data.get(&TypeId::of::<T>())
161 .map(|any| unsafe { any.downcast_ref_unchecked::<T>() })
162 }
163
164 /// Retrieve a mutable reference to the value stored in the map for the type `T`, if it exists.
165 pub fn get_mut<T: Any + 'static>(&mut self) -> Option<&mut T> {
166 self.data.get_mut(&TypeId::of::<T>())
167 .map(|any| unsafe { any.downcast_mut_unchecked::<T>() })
168 }
169
170 /// Set the value contained in the map for the type `T`.
171 /// If there is a previous value stored, it will be returned.
172 pub fn insert<T: Any + 'static>(&mut self, value: T) -> Option<T> {
173 self.data.insert(TypeId::of::<T>(), box value as Box<Any>)
174 .map(|any| *unsafe { any.downcast_unchecked::<T>() })
175 }
176
177 /// Remove and return the value for the type `T` if it existed.
178 pub fn remove<T: Any + 'static>(&mut self) -> Option<T> {
179 self.data.remove(&TypeId::of::<T>())
180 .map(|any| *unsafe { any.downcast_unchecked::<T>() })
181 }
182
183 /// Does a value of type `T` exist?
184 pub fn contains<T: Any + 'static>(&self) -> bool {
185 self.data.contains_key(&TypeId::of::<T>())
186 }
187
188 /// Gets the given key's corresponding entry in the map for in-place manipulation
189 pub fn entry<T: Any + 'static>(&mut self) -> Entry<T> {
190 match self.data.entry(TypeId::of::<T>()) {
191 hash_map::Occupied(e) => Occupied(OccupiedEntry { entry: e }),
192 hash_map::Vacant(e) => Vacant(VacantEntry { entry: e }),
193 }
194 }
195
196 /// Returns the number of items in the collection.
197 pub fn len(&self) -> uint {
198 self.data.len()
199 }
200
201 /// Returns true if there are no items in the collection.
202 pub fn is_empty(&self) -> bool {
203 self.data.is_empty()
204 }
205
206 /// Removes all items from the collection.
207 pub fn clear(&mut self) {
208 self.data.clear();
209 }
210 }
211
212 /// A view into a single occupied location in a HashMap
213 pub struct OccupiedEntry<'a, V: 'a> {
214 entry: hash_map::OccupiedEntry<'a, TypeId, Box<Any + 'static>>,
215 }
216
217 /// A view into a single empty location in a HashMap
218 pub struct VacantEntry<'a, V: 'a> {
219 entry: hash_map::VacantEntry<'a, TypeId, Box<Any + 'static>>,
220 }
221
222 /// A view into a single location in a map, which may be vacant or occupied
223 pub enum Entry<'a, V: 'a> {
224 /// An occupied Entry
225 Occupied(OccupiedEntry<'a, V>),
226 /// A vacant Entry
227 Vacant(VacantEntry<'a, V>),
228 }
229
230 impl<'a, V: 'static> OccupiedEntry<'a, V> {
231 /// Gets a reference to the value in the entry
232 pub fn get(&self) -> &V {
233 unsafe { self.entry.get().downcast_ref_unchecked() }
234 }
235
236 /// Gets a mutable reference to the value in the entry
237 pub fn get_mut(&mut self) -> &mut V {
238 unsafe { self.entry.get_mut().downcast_mut_unchecked() }
239 }
240
241 /// Converts the OccupiedEntry into a mutable reference to the value in the entry
242 /// with a lifetime bound to the map itself
243 pub fn into_mut(self) -> &'a mut V {
244 unsafe { self.entry.into_mut().downcast_mut_unchecked() }
245 }
246
247 /// Sets the value of the entry, and returns the entry's old value
248 pub fn set(&mut self, value: V) -> V {
249 unsafe { *self.entry.set(box value as Box<Any + 'static>).downcast_unchecked() }
250 }
251
252 /// Takes the value out of the entry, and returns it
253 pub fn take(self) -> V {
254 unsafe { *self.entry.take().downcast_unchecked() }
255 }
256 }
257
258 impl<'a, V: 'static> VacantEntry<'a, V> {
259 /// Sets the value of the entry with the VacantEntry's key,
260 /// and returns a mutable reference to it
261 pub fn set(self, value: V) -> &'a mut V {
262 unsafe { self.entry.set(box value as Box<Any + 'static>).downcast_mut_unchecked() }
263 }
264 }
265
266 #[bench]
267 fn bench_insertion(b: &mut ::test::Bencher) {
268 b.iter(|| {
269 let mut data = AnyMap::new();
270 for _ in range(0u, 100) {
271 let _ = data.insert(42i);
272 }
273 })
274 }
275
276 #[bench]
277 fn bench_get_missing(b: &mut ::test::Bencher) {
278 b.iter(|| {
279 let data = AnyMap::new();
280 for _ in range(0u, 100) {
281 assert_eq!(data.get(), None::<&int>);
282 }
283 })
284 }
285
286 #[bench]
287 fn bench_get_present(b: &mut ::test::Bencher) {
288 b.iter(|| {
289 let mut data = AnyMap::new();
290 let _ = data.insert(42i);
291 // These inner loops are a feeble attempt to drown the other factors.
292 for _ in range(0u, 100) {
293 assert_eq!(data.get(), Some(&42i));
294 }
295 })
296 }
297
298 #[test]
299 fn test_entry() {
300 #[deriving(Show, PartialEq)] struct A(int);
301 #[deriving(Show, PartialEq)] struct B(int);
302 #[deriving(Show, PartialEq)] struct C(int);
303 #[deriving(Show, PartialEq)] struct D(int);
304 #[deriving(Show, PartialEq)] struct E(int);
305 #[deriving(Show, PartialEq)] struct F(int);
306 #[deriving(Show, PartialEq)] struct J(int);
307
308 let mut map: AnyMap = AnyMap::new();
309 assert_eq!(map.insert(A(10)), None);
310 assert_eq!(map.insert(B(20)), None);
311 assert_eq!(map.insert(C(30)), None);
312 assert_eq!(map.insert(D(40)), None);
313 assert_eq!(map.insert(E(50)), None);
314 assert_eq!(map.insert(F(60)), None);
315
316 // Existing key (insert)
317 match map.entry::<A>() {
318 Vacant(_) => unreachable!(),
319 Occupied(mut view) => {
320 assert_eq!(view.get(), &A(10));
321 assert_eq!(view.set(A(100)), A(10));
322 }
323 }
324 assert_eq!(map.get::<A>().unwrap(), &A(100));
325 assert_eq!(map.len(), 6);
326
327
328 // Existing key (update)
329 match map.entry::<B>() {
330 Vacant(_) => unreachable!(),
331 Occupied(mut view) => {
332 let v = view.get_mut();
333 let new_v = B(v.0 * 10);
334 *v = new_v;
335 }
336 }
337 assert_eq!(map.get().unwrap(), &B(200));
338 assert_eq!(map.len(), 6);
339
340
341 // Existing key (take)
342 match map.entry::<C>() {
343 Vacant(_) => unreachable!(),
344 Occupied(view) => {
345 assert_eq!(view.take(), C(30));
346 }
347 }
348 assert_eq!(map.get::<C>(), None);
349 assert_eq!(map.len(), 5);
350
351
352 // Inexistent key (insert)
353 match map.entry::<J>() {
354 Occupied(_) => unreachable!(),
355 Vacant(view) => {
356 assert_eq!(*view.set(J(1000)), J(1000));
357 }
358 }
359 assert_eq!(map.get::<J>().unwrap(), &J(1000));
360 assert_eq!(map.len(), 6);
361 }