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