80e51045613f78400272a47d927bd1684889b108
[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)]
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::hash::{Hash, Hasher, Writer};
17 use std::mem::{transmute, transmute_copy};
18 use std::raw::TraitObject;
19
20 struct TypeIdHasher;
21
22 struct TypeIdState {
23 value: u64,
24 }
25
26 impl Writer for TypeIdState {
27 #[inline(always)]
28 fn write(&mut self, bytes: &[u8]) {
29 // This expects to receive one and exactly one 64-bit value
30 debug_assert!(bytes.len() == 8);
31 unsafe {
32 std::ptr::copy_nonoverlapping_memory(&mut self.value,
33 transmute(&bytes[0]),
34 1)
35 }
36 }
37 }
38
39 impl Hasher<TypeIdState> for TypeIdHasher {
40 fn hash<Sized? T: Hash<TypeIdState>>(&self, value: &T) -> u64 {
41 let mut state = TypeIdState {
42 value: 0,
43 };
44 value.hash(&mut state);
45 state.value
46 }
47 }
48
49 /// An extension of `AnyRefExt` allowing unchecked downcasting of trait objects to `&T`.
50 trait UncheckedAnyRefExt<'a> {
51 /// Returns a reference to the boxed value, assuming that it is of type `T`. This should only be
52 /// called if you are ABSOLUTELY CERTAIN of `T` as you will get really wacky output if it’s not.
53 unsafe fn downcast_ref_unchecked<T: 'static>(self) -> &'a T;
54 }
55
56 impl<'a> UncheckedAnyRefExt<'a> for &'a Any + 'a {
57 #[inline]
58 unsafe fn downcast_ref_unchecked<T: 'static>(self) -> &'a T {
59 // Get the raw representation of the trait object
60 let to: TraitObject = transmute_copy(&self);
61
62 // Extract the data pointer
63 transmute(to.data)
64 }
65 }
66
67 /// An extension of `AnyMutRefExt` allowing unchecked downcasting of trait objects to `&mut T`.
68 trait UncheckedAnyMutRefExt<'a> {
69 /// Returns a reference to the boxed value, assuming that it is of type `T`. This should only be
70 /// called if you are ABSOLUTELY CERTAIN of `T` as you will get really wacky output if it’s not.
71 unsafe fn downcast_mut_unchecked<T: 'static>(self) -> &'a mut T;
72 }
73
74 impl<'a> UncheckedAnyMutRefExt<'a> for &'a mut Any + 'a {
75 #[inline]
76 unsafe fn downcast_mut_unchecked<T: 'static>(self) -> &'a mut T {
77 // Get the raw representation of the trait object
78 let to: TraitObject = transmute_copy(&self);
79
80 // Extract the data pointer
81 transmute(to.data)
82 }
83 }
84
85 /// An extension of `BoxAny` allowing unchecked downcasting of trait objects to `Box<T>`.
86 trait UncheckedBoxAny {
87 /// Returns the boxed value, assuming that it is of type `T`. This should only be called if you
88 /// are ABSOLUTELY CERTAIN of `T` as you will get really wacky output if it’s not.
89 unsafe fn downcast_unchecked<T: 'static>(self) -> Box<T>;
90 }
91
92 impl UncheckedBoxAny for Box<Any + 'static> {
93 #[inline]
94 unsafe fn downcast_unchecked<T: 'static>(self) -> Box<T> {
95 // Get the raw representation of the trait object
96 let to: TraitObject = *transmute::<&Box<Any>, &TraitObject>(&self);
97
98 // Prevent destructor on self being run
99 forget(self);
100
101 // Extract the data pointer
102 transmute(to.data)
103 }
104 }
105
106 /// A map containing zero or one values for any given type and allowing convenient,
107 /// type-safe access to those values.
108 ///
109 /// ```rust
110 /// # use anymap::AnyMap;
111 /// let mut data = AnyMap::new();
112 /// assert_eq!(data.get(), None::<&int>);
113 /// data.insert(42i);
114 /// assert_eq!(data.get(), Some(&42i));
115 /// data.remove::<int>();
116 /// assert_eq!(data.get::<int>(), None);
117 ///
118 /// #[deriving(PartialEq, Show)]
119 /// struct Foo {
120 /// str: String,
121 /// }
122 ///
123 /// assert_eq!(data.get::<Foo>(), None);
124 /// data.insert(Foo { str: "foo".to_string() });
125 /// assert_eq!(data.get(), Some(&Foo { str: "foo".to_string() }));
126 /// data.get_mut::<Foo>().map(|foo| foo.str.push('t'));
127 /// assert_eq!(data.get::<Foo>().unwrap().str.as_slice(), "foot");
128 /// ```
129 ///
130 /// Values containing non-static references are not permitted.
131 pub struct AnyMap {
132 data: HashMap<TypeId, Box<Any + 'static>, TypeIdHasher>,
133 }
134
135 impl AnyMap {
136 /// Construct a new `AnyMap`.
137 pub fn new() -> AnyMap {
138 AnyMap {
139 data: HashMap::with_hasher(TypeIdHasher),
140 }
141 }
142 }
143
144 impl AnyMap {
145 /// Deprecated: Renamed to `get`.
146 #[deprecated = "Renamed to `get`"]
147 pub fn find<T: Any + 'static>(&self) -> Option<&T> {
148 self.get::<T>()
149 }
150
151 /// Deprecated: Renamed to `get_mut`.
152 #[deprecated = "Renamed to `get_mut`"]
153 pub fn find_mut<T: Any + 'static>(&mut self) -> Option<&mut T> {
154 self.get_mut::<T>()
155 }
156
157 /// Retrieve the value stored in the map for the type `T`, if it exists.
158 pub fn get<T: Any + 'static>(&self) -> Option<&T> {
159 self.data.get(&TypeId::of::<T>())
160 .map(|any| unsafe { any.downcast_ref_unchecked::<T>() })
161 }
162
163 /// Retrieve a mutable reference to the value stored in the map for the type `T`, if it exists.
164 pub fn get_mut<T: Any + 'static>(&mut self) -> Option<&mut T> {
165 self.data.get_mut(&TypeId::of::<T>())
166 .map(|any| unsafe { any.downcast_mut_unchecked::<T>() })
167 }
168
169 /// Set the value contained in the map for the type `T`.
170 /// If there is a previous value stored, it will be returned.
171 pub fn insert<T: Any + 'static>(&mut self, value: T) -> Option<T> {
172 self.data.insert(TypeId::of::<T>(), box value as Box<Any>)
173 .map(|any| *unsafe { any.downcast_unchecked::<T>() })
174 }
175
176 /// Remove and return the value for the type `T` if it existed.
177 pub fn remove<T: Any + 'static>(&mut self) -> Option<T> {
178 self.data.remove(&TypeId::of::<T>())
179 .map(|any| *unsafe { any.downcast_unchecked::<T>() })
180 }
181
182 /// Does a value of type `T` exist?
183 pub fn contains<T: Any + 'static>(&self) -> bool {
184 self.data.contains_key(&TypeId::of::<T>())
185 }
186
187 /// Returns the number of items in the collection.
188 pub fn len(&self) -> uint {
189 self.data.len()
190 }
191
192 /// Returns true if there are no items in the collection.
193 pub fn is_empty(&self) -> bool {
194 self.data.is_empty()
195 }
196
197 /// Removes all items from the collection.
198 pub fn clear(&mut self) {
199 self.data.clear();
200 }
201 }
202
203 #[bench]
204 fn bench_insertion(b: &mut ::test::Bencher) {
205 b.iter(|| {
206 let mut data = AnyMap::new();
207 for _ in range(0u, 100) {
208 let _ = data.insert(42i);
209 }
210 })
211 }
212
213 #[bench]
214 fn bench_get_missing(b: &mut ::test::Bencher) {
215 b.iter(|| {
216 let data = AnyMap::new();
217 for _ in range(0u, 100) {
218 assert_eq!(data.get(), None::<&int>);
219 }
220 })
221 }
222
223 #[bench]
224 fn bench_get_present(b: &mut ::test::Bencher) {
225 b.iter(|| {
226 let mut data = AnyMap::new();
227 let _ = data.insert(42i);
228 // These inner loops are a feeble attempt to drown the other factors.
229 for _ in range(0u, 100) {
230 assert_eq!(data.get(), Some(&42i));
231 }
232 })
233 }