1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#![deny(missing_docs)]
#![allow(mutable_transmutes)]
#![cfg_attr(feature = "unstable", feature(core_intrinsics))]
use std::cell::RefCell;
use std::any::{ TypeId, Any };
use std::collections::HashMap;
use std::collections::hash_map::Entry::{ Occupied, Vacant };
use std::ops::{ Deref, DerefMut };
use std::marker::PhantomData;
thread_local!(static KEY_CURRENT: RefCell<HashMap<TypeId, usize>>
= RefCell::new(HashMap::new()));
pub struct CurrentGuard<'a, T> where T: Any {
_val: &'a mut T,
old_ptr: Option<usize>
}
#[allow(trivial_casts)]
impl<'a, T> CurrentGuard<'a, T> where T: Any {
pub fn new(val: &mut T) -> CurrentGuard<T> {
let id = TypeId::of::<T>();
let ptr = val as *mut T as usize;
let old_ptr = KEY_CURRENT.with(|current| {
match current.borrow_mut().entry(id) {
Occupied(mut entry) => Some(entry.insert(ptr)),
Vacant(entry) => {
entry.insert(ptr);
None
}
}
});
CurrentGuard { old_ptr: old_ptr, _val: val }
}
}
impl<'a, T> Drop for CurrentGuard<'a, T> where T: Any {
fn drop(&mut self) {
let id = TypeId::of::<T>();
match self.old_ptr {
None => {
KEY_CURRENT.with(|current| {
current.borrow_mut().remove(&id);
});
return;
}
Some(old_ptr) => {
KEY_CURRENT.with(|current| {
match current.borrow_mut().entry(id) {
Occupied(mut entry) => { entry.insert(old_ptr); }
Vacant(entry) => { entry.insert(old_ptr); }
};
});
}
};
}
}
pub struct Current<T>(PhantomData<T>);
impl<T> Current<T> where T: Any {
pub unsafe fn new() -> Current<T> { Current(PhantomData) }
pub unsafe fn current(&mut self) -> Option<&mut T> {
use std::mem::transmute;
let id = TypeId::of::<T>();
let ptr: Option<usize> = KEY_CURRENT.with(|current| {
current.borrow().get(&id).map(|id| *id)
});
let ptr = match ptr { None => { return None; } Some(x) => x };
Some(transmute(ptr as *mut T))
}
pub unsafe fn current_unwrap(&mut self) -> &mut T {
#[cfg(feature = "unstable")]
fn report_unstable<T>() -> ! {
use std::intrinsics::type_name;
panic!("No current `{}` is set", unsafe { type_name::<T>() });
}
#[cfg(not(feature = "unstable"))]
fn report_unstable<T>() -> ! {
panic!("No current object is set of this type");
}
match self.current() {
None => report_unstable::<T>(),
Some(x) => x
}
}
}
impl<T> Deref for Current<T> where T: Any {
type Target = T;
#[inline(always)]
fn deref<'a>(&'a self) -> &'a T {
use std::mem::transmute;
unsafe {
transmute::<_, &'a mut Current<T>>(self).current_unwrap()
}
}
}
impl<T> DerefMut for Current<T> where T: Any {
#[inline(always)]
fn deref_mut<'a>(&'a mut self) -> &'a mut T {
unsafe { self.current_unwrap() }
}
}