f5ee7b3831e61945b9e1e85daba10c0e6c1960cc
[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_id = "anymap#0.9.0"]
4 #![crate_type = "rlib"]
5 #![crate_type = "dylib"]
6 #![feature(default_type_params)]
7 #![warn(unnecessary_qualification, non_uppercase_statics,
8 variant_size_difference, managed_heap_memory, unnecessary_typecast,
9 missing_doc, unused_result)]
10
11 #[cfg(test)]
12 extern crate test;
13
14 use std::any::Any;
15 use std::intrinsics::TypeId;
16 use std::collections::{Collection, HashMap, Mutable};
17 use std::hash::{Hash, Hasher, Writer};
18 use std::mem::{transmute, transmute_copy};
19 use std::raw::TraitObject;
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<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 as_ref_unchecked<T: 'static>(self) -> &'a T;
55 }
56
57 impl<'a> UncheckedAnyRefExt<'a> for &'a Any {
58 #[inline]
59 unsafe fn as_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 as_mut_unchecked<T: 'static>(self) -> &'a mut T;
73 }
74
75 impl<'a> UncheckedAnyMutRefExt<'a> for &'a mut Any {
76 #[inline]
77 unsafe fn as_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 /// A map containing zero or one values for any given type and allowing convenient,
87 /// type-safe access to those values.
88 ///
89 /// ```rust
90 /// # use anymap::AnyMap;
91 /// let mut data = AnyMap::new();
92 /// assert_eq!(data.find(), None::<&int>);
93 /// data.insert(42i);
94 /// assert_eq!(data.find(), Some(&42i));
95 /// data.remove::<int>();
96 /// assert_eq!(data.find::<int>(), None);
97 ///
98 /// #[deriving(PartialEq, Show)]
99 /// struct Foo {
100 /// str: String,
101 /// }
102 ///
103 /// assert_eq!(data.find::<Foo>(), None);
104 /// data.insert(Foo { str: "foo".to_string() });
105 /// assert_eq!(data.find(), Some(&Foo { str: "foo".to_string() }));
106 /// data.find_mut::<Foo>().map(|foo| foo.str.push_char('t'));
107 /// assert_eq!(data.find::<Foo>().unwrap().str.as_slice(), "foot");
108 /// ```
109 ///
110 /// Values containing non-static references are not permitted.
111 pub struct AnyMap {
112 data: HashMap<TypeId, Box<Any>, TypeIdHasher>,
113 }
114
115 impl AnyMap {
116 /// Construct a new `AnyMap`.
117 pub fn new() -> AnyMap {
118 AnyMap {
119 data: HashMap::with_hasher(TypeIdHasher),
120 }
121 }
122 }
123
124 impl AnyMap {
125 /// Retrieve the value stored in the map for the type `T`, if it exists.
126 pub fn find<'a, T: 'static>(&'a self) -> Option<&'a T> {
127 self.data.find(&TypeId::of::<T>()).map(|any| unsafe { any.as_ref_unchecked::<T>() })
128 }
129
130 /// Retrieve a mutable reference to the value stored in the map for the type `T`, if it exists.
131 pub fn find_mut<'a, T: 'static>(&'a mut self) -> Option<&'a mut T> {
132 self.data.find_mut(&TypeId::of::<T>()).map(|any| unsafe { any.as_mut_unchecked::<T>() })
133 }
134
135 /// Set the value contained in the map for the type `T`.
136 /// This will override any previous value stored.
137 pub fn insert<T: 'static>(&mut self, value: T) {
138 self.data.insert(TypeId::of::<T>(), box value as Box<Any>);
139 }
140
141 /// Remove the value for the type `T` if it existed.
142 pub fn remove<T: 'static>(&mut self) {
143 self.data.remove(&TypeId::of::<T>());
144 }
145 }
146
147 impl Collection for AnyMap {
148 fn len(&self) -> uint {
149 self.data.len()
150 }
151
152 fn is_empty(&self) -> bool {
153 self.data.is_empty()
154 }
155 }
156
157 impl Mutable for AnyMap {
158 fn clear(&mut self) {
159 self.data.clear();
160 }
161 }
162
163 #[bench]
164 fn bench_insertion(b: &mut ::test::Bencher) {
165 b.iter(|| {
166 let mut data = AnyMap::new();
167 for _ in range(0u, 100) {
168 data.insert(42i);
169 }
170 })
171 }
172
173 #[bench]
174 fn bench_find_missing(b: &mut ::test::Bencher) {
175 b.iter(|| {
176 let data = AnyMap::new();
177 for _ in range(0u, 100) {
178 assert_eq!(data.find(), None::<&int>);
179 }
180 })
181 }
182
183 #[bench]
184 fn bench_find_present(b: &mut ::test::Bencher) {
185 b.iter(|| {
186 let mut data = AnyMap::new();
187 data.insert(42i);
188 // These inner loops are a feeble attempt to drown the other factors.
189 for _ in range(0u, 100) {
190 assert_eq!(data.find(), Some(&42i));
191 }
192 })
193 }