1 use std::any::{Any, TypeId};
2 use std::cell::UnsafeCell;
3 use std::collections::HashMap;
4 use std::fmt;
5 use std::mem;
6 use std::ops::Deref;
7 
8 pub struct OptCell<T>(UnsafeCell<Option<T>>);
9 
10 impl<T> OptCell<T> {
11     #[inline]
new(val: Option<T>) -> OptCell<T>12     pub fn new(val: Option<T>) -> OptCell<T> {
13         OptCell(UnsafeCell::new(val))
14     }
15 
16     #[inline]
set(&self, val: T)17     pub fn set(&self, val: T) {
18         unsafe {
19             let opt = self.0.get();
20             debug_assert!((*opt).is_none());
21             *opt = Some(val)
22         }
23     }
24 
25     #[inline]
get_mut(&mut self) -> &mut T26     pub unsafe fn get_mut(&mut self) -> &mut T {
27         let opt = &mut *self.0.get();
28         opt.as_mut().unwrap()
29     }
30 }
31 
32 impl<T> Deref for OptCell<T> {
33     type Target = Option<T>;
34     #[inline]
deref(&self) -> &Option<T>35     fn deref(&self) -> &Option<T> {
36         unsafe { &*self.0.get() }
37     }
38 }
39 
40 impl<T: Clone> Clone for OptCell<T> {
41     #[inline]
clone(&self) -> OptCell<T>42     fn clone(&self) -> OptCell<T> {
43         OptCell::new((**self).clone())
44     }
45 }
46 
47 pub struct PtrMapCell<V: ?Sized>(UnsafeCell<PtrMap<Box<V>>>);
48 
49 #[derive(Clone, Debug)]
50 enum PtrMap<T> {
51     Empty,
52     One(TypeId, T),
53     Many(HashMap<TypeId, T>)
54 }
55 
56 impl<V: ?Sized + fmt::Debug + Any + 'static> PtrMapCell<V> {
57     #[inline]
new() -> PtrMapCell<V>58     pub fn new() -> PtrMapCell<V> {
59         PtrMapCell(UnsafeCell::new(PtrMap::Empty))
60     }
61 
62     #[inline]
get(&self, key: TypeId) -> Option<&V>63     pub fn get(&self, key: TypeId) -> Option<&V> {
64         let map = unsafe { &*self.0.get() };
65         match *map {
66             PtrMap::Empty => None,
67             PtrMap::One(id, ref v) => if id == key {
68                 Some(v)
69             } else {
70                 None
71             },
72             PtrMap::Many(ref hm) => hm.get(&key)
73         }.map(|val| &**val)
74     }
75 
76     #[inline]
get_mut(&mut self, key: TypeId) -> Option<&mut V>77     pub fn get_mut(&mut self, key: TypeId) -> Option<&mut V> {
78         let map = unsafe { &mut *self.0.get() };
79         match *map {
80             PtrMap::Empty => None,
81             PtrMap::One(id, ref mut v) => if id == key {
82                 Some(v)
83             } else {
84                 None
85             },
86             PtrMap::Many(ref mut hm) => hm.get_mut(&key)
87         }.map(|val| &mut **val)
88     }
89 
90     #[inline]
insert(&self, key: TypeId, val: Box<V>)91     pub unsafe fn insert(&self, key: TypeId, val: Box<V>) {
92         let map = &mut *self.0.get();
93         match *map {
94             PtrMap::Empty => *map = PtrMap::One(key, val),
95             PtrMap::One(..) => {
96                 let one = mem::replace(map, PtrMap::Empty);
97                 match one {
98                     PtrMap::One(id, one) => {
99                         debug_assert!(id != key);
100                         let mut hm = HashMap::with_capacity(2);
101                         hm.insert(id, one);
102                         hm.insert(key, val);
103                         mem::replace(map, PtrMap::Many(hm));
104                     },
105                     _ => unreachable!()
106                 }
107             },
108             PtrMap::Many(ref mut hm) => { hm.insert(key, val); }
109         }
110     }
111 
112     #[inline]
one(&self) -> &V113     pub unsafe fn one(&self) -> &V {
114         let map = &*self.0.get();
115         match *map {
116             PtrMap::One(_, ref one) => one,
117             _ => panic!("not PtrMap::One value, {:?}", *map)
118         }
119     }
120 }
121 
122 impl<V: ?Sized + fmt::Debug + Any + 'static> Clone for PtrMapCell<V> where Box<V>: Clone {
123     #[inline]
clone(&self) -> PtrMapCell<V>124     fn clone(&self) -> PtrMapCell<V> {
125         let cell = PtrMapCell::new();
126         unsafe {
127             *cell.0.get() = (&*self.0.get()).clone()
128         }
129         cell
130     }
131 }
132 
133 #[cfg(test)]
134 mod test {
135     use std::any::TypeId;
136     use super::*;
137 
138     #[test]
test_opt_cell_set()139     fn test_opt_cell_set() {
140         let one:OptCell<u32> = OptCell::new(None);
141         one.set(1);
142         assert_eq!(*one,Some(1));
143     }
144 
145     #[test]
test_opt_cell_clone()146     fn test_opt_cell_clone() {
147         let one:OptCell<u32> = OptCell::new(Some(3));
148         let stored = *one.clone();
149         assert_eq!(stored,Some(3));
150     }
151 
152 
153     #[test]
test_ptr_map_cell_none()154     fn test_ptr_map_cell_none() {
155         let type_id = TypeId::of::<u32>();
156         let pm:PtrMapCell<u32> = PtrMapCell::new();
157         assert_eq!(pm.get(type_id),None);
158     }
159 
160     #[test]
test_ptr_map_cell_one()161     fn test_ptr_map_cell_one() {
162         let type_id = TypeId::of::<String>();
163         let pm:PtrMapCell<String> = PtrMapCell::new();
164         unsafe { pm.insert(type_id, Box::new("a".to_string())); }
165         assert_eq!(pm.get(type_id), Some(&"a".to_string()));
166         assert_eq!(unsafe {pm.one()}, "a");
167     }
168 
169     #[test]
test_ptr_map_cell_two()170     fn test_ptr_map_cell_two() {
171         let type_id = TypeId::of::<String>();
172         let type_id2 = TypeId::of::<Vec<u8>>();
173         let pm:PtrMapCell<String> = PtrMapCell::new();
174         unsafe { pm.insert(type_id, Box::new("a".to_string())); }
175         unsafe { pm.insert(type_id2, Box::new("b".to_string())); }
176         assert_eq!(pm.get(type_id), Some(&"a".to_string()));
177         assert_eq!(pm.get(type_id2), Some(&"b".to_string()));
178     }
179 
180     #[test]
test_ptr_map_cell_many()181     fn test_ptr_map_cell_many() {
182         let id1 = TypeId::of::<String>();
183         let id2 = TypeId::of::<Vec<u8>>();
184         let id3 = TypeId::of::<OptCell<String>>();
185         let pm:PtrMapCell<String> = PtrMapCell::new();
186         unsafe { pm.insert(id1, Box::new("a".to_string())); }
187         unsafe { pm.insert(id2, Box::new("b".to_string())); }
188         unsafe { pm.insert(id3, Box::new("c".to_string())); }
189         assert_eq!(pm.get(id1), Some(&"a".to_string()));
190         assert_eq!(pm.get(id2), Some(&"b".to_string()));
191         assert_eq!(pm.get(id3), Some(&"c".to_string()));
192     }
193 
194 
195     #[test]
test_ptr_map_cell_clone()196     fn test_ptr_map_cell_clone() {
197         let type_id = TypeId::of::<String>();
198         let pm:PtrMapCell<String> = PtrMapCell::new();
199         unsafe { pm.insert(type_id, Box::new("a".to_string())); }
200         let cloned = pm.clone();
201         assert_eq!(cloned.get(type_id), Some(&"a".to_string()));
202     }
203 
204 }
205