#![deny(missing_docs)]
#![feature(core_intrinsics)]
#![allow(mutable_transmutes)]
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 {
match self.current() {
None => {
use std::intrinsics::type_name;
panic!("No current `{}` is set", type_name::<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() }
}
}