2d03c5635901c75b34b047dd65cac6109958d05b
[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"]
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, deprecated_owned_vector)]
10
11 #[cfg(test)]
12 extern crate test;
13
14 use std::any::{Any, AnyRefExt, AnyMutRefExt};
15 use std::intrinsics::TypeId;
16 use std::collections::HashMap;
17 use std::hash::{Hash, Hasher, Writer};
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 std::mem::transmute(&bytes[0]),
33 1)
34 }
35 }
36 }
37
38 impl Hasher<TypeIdState> for TypeIdHasher {
39 fn hash<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 /// A map containing zero or one values for any given type and allowing convenient,
49 /// type-safe access to those values.
50 ///
51 /// ```rust
52 /// # use anymap::AnyMap;
53 /// let mut data = AnyMap::new();
54 /// assert_eq!(data.find(), None::<&int>);
55 /// data.insert(42i);
56 /// assert_eq!(data.find(), Some(&42i));
57 /// data.remove::<int>();
58 /// assert_eq!(data.find::<int>(), None);
59 ///
60 /// #[deriving(PartialEq, Show)]
61 /// struct Foo {
62 /// str: String,
63 /// }
64 ///
65 /// assert_eq!(data.find::<Foo>(), None);
66 /// data.insert(Foo { str: "foo".to_string() });
67 /// assert_eq!(data.find(), Some(&Foo { str: "foo".to_string() }));
68 /// data.find_mut::<Foo>().map(|foo| foo.str.push_char('t'));
69 /// assert_eq!(data.find::<Foo>().unwrap().str.as_slice(), "foot");
70 /// ```
71 ///
72 /// Values containing non-static references are not permitted.
73 pub struct AnyMap {
74 data: HashMap<TypeId, Box<Any>:'static, TypeIdHasher>,
75 }
76
77 impl AnyMap {
78 /// Construct a new `AnyMap`.
79 pub fn new() -> AnyMap {
80 AnyMap {
81 data: HashMap::with_hasher(TypeIdHasher),
82 }
83 }
84 }
85
86 impl AnyMap {
87 /// Retrieve the value stored in the map for the type `T`, if it exists.
88 pub fn find<'a, T: 'static>(&'a self) -> Option<&'a T> {
89 self.data.find(&TypeId::of::<T>()).and_then(|any| any.as_ref::<T>())
90 }
91
92 /// Retrieve a mutable reference to the value stored in the map for the type `T`, if it exists.
93 pub fn find_mut<'a, T: 'static>(&'a mut self) -> Option<&'a mut T> {
94 self.data.find_mut(&TypeId::of::<T>()).and_then(|any| any.as_mut::<T>())
95 }
96
97 /// Set the value contained in the map for the type `T`.
98 /// This will override any previous value stored.
99 pub fn insert<T: 'static>(&mut self, value: T) {
100 self.data.insert(TypeId::of::<T>(), box value as Box<Any>:'static);
101 }
102
103 /// Remove the value for the type `T` if it existed.
104 pub fn remove<T: 'static>(&mut self) {
105 self.data.remove(&TypeId::of::<T>());
106 }
107 }
108
109 #[bench]
110 fn bench_insertion(b: &mut ::test::Bencher) {
111 b.iter(|| {
112 let mut data = AnyMap::new();
113 data.insert(42i);
114 })
115 }
116
117 #[bench]
118 fn bench_find_missing(b: &mut ::test::Bencher) {
119 b.iter(|| {
120 let data = AnyMap::new();
121 assert_eq!(data.find(), None::<&int>);
122 })
123 }
124
125 #[bench]
126 fn bench_find_present(b: &mut ::test::Bencher) {
127 b.iter(|| {
128 let mut data = AnyMap::new();
129 data.insert(42i);
130 assert_eq!(data.find(), Some(&42i));
131 })
132 }