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