current/
lib.rs

1#![deny(missing_docs)]
2#![feature(core_intrinsics)]
3#![allow(mutable_transmutes)]
4
5
6//! A library for setting current values for stack scope,
7//! such as application structure.
8
9use std::cell::RefCell;
10use std::any::{ TypeId, Any };
11use std::collections::HashMap;
12use std::collections::hash_map::Entry::{ Occupied, Vacant };
13use std::ops::{ Deref, DerefMut };
14use std::marker::PhantomData;
15
16// Stores the current pointers for concrete types.
17thread_local!(static KEY_CURRENT: RefCell<HashMap<TypeId, usize>>
18    = RefCell::new(HashMap::new()));
19
20/// Puts back the previous current pointer.
21pub struct CurrentGuard<'a, T> where T: Any {
22    _val: &'a mut T,
23    old_ptr: Option<usize>
24}
25
26#[allow(trivial_casts)]
27impl<'a, T> CurrentGuard<'a, T> where T: Any {
28    /// Creates a new current guard.
29    pub fn new(val: &mut T) -> CurrentGuard<T> {
30        let id = TypeId::of::<T>();
31        let ptr = val as *mut T as usize;
32        let old_ptr = KEY_CURRENT.with(|current| {
33            match current.borrow_mut().entry(id) {
34                Occupied(mut entry) => Some(entry.insert(ptr)),
35                Vacant(entry) => {
36                    entry.insert(ptr);
37                    None
38                }
39            }
40        });
41        CurrentGuard { old_ptr: old_ptr, _val: val }
42    }
43}
44
45impl<'a, T> Drop for CurrentGuard<'a, T> where T: Any {
46    fn drop(&mut self) {
47        let id = TypeId::of::<T>();
48        match self.old_ptr {
49            None => {
50                KEY_CURRENT.with(|current| {
51                    current.borrow_mut().remove(&id);
52                });
53                return;
54            }
55            Some(old_ptr) => {
56                KEY_CURRENT.with(|current| {
57                    match current.borrow_mut().entry(id) {
58                        Occupied(mut entry) => { entry.insert(old_ptr); }
59                        Vacant(entry) => { entry.insert(old_ptr); }
60                    };
61                });
62            }
63        };
64    }
65}
66
67/// The current value of a type.
68pub struct Current<T>(PhantomData<T>);
69
70impl<T> Current<T> where T: Any {
71    /// Creates a new current object
72    pub unsafe fn new() -> Current<T> { Current(PhantomData) }
73
74    /// Gets mutable reference to current object.
75    /// Requires mutable reference to prevent access to globals in safe code,
76    /// and to prevent mutable borrows of same value in scope.
77    /// Is unsafe because returned reference inherits lifetime from argument.
78    pub unsafe fn current(&mut self) -> Option<&mut T> {
79        use std::mem::transmute;
80        let id = TypeId::of::<T>();
81        let ptr: Option<usize> = KEY_CURRENT.with(|current| {
82                current.borrow().get(&id).map(|id| *id)
83            });
84        let ptr = match ptr { None => { return None; } Some(x) => x };
85        Some(transmute(ptr as *mut T))
86    }
87
88    /// Unwraps mutable reference to current object,
89    /// but with nicer error message.
90    pub unsafe fn current_unwrap(&mut self) -> &mut T {
91        match self.current() {
92            None => {
93                use std::intrinsics::type_name;
94                panic!("No current `{}` is set", type_name::<T>());
95            }
96            Some(x) => x
97        }
98    }
99}
100
101impl<T> Deref for Current<T> where T: Any {
102    type Target = T;
103
104    #[inline(always)]
105    fn deref<'a>(&'a self) -> &'a T {
106        use std::mem::transmute;
107        unsafe {
108            // Current does not contain anything,
109            // so it is safe to transmute to mutable.
110            transmute::<_, &'a mut Current<T>>(self).current_unwrap()
111        }
112    }
113}
114
115impl<T> DerefMut for Current<T> where T: Any {
116    #[inline(always)]
117    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
118        unsafe { self.current_unwrap() }
119    }
120}