execution_context/
data.rs

1use im::hashmap::HashMap;
2use std::any::TypeId;
3use std::fmt;
4use std::hash::{BuildHasherDefault, Hasher};
5use std::mem;
6use std::sync::Arc;
7use std::ops::Deref;
8
9use ctx::ExecutionContext;
10
11/// A macro to create a `static` of type `FlowLocal`
12///
13/// This macro is intentionally similar to the `thread_local!`, and creates a
14/// `static` which has a `get_mut` method to access the data on a flow.
15///
16/// The data associated with each flow local is per-flow, so different flows
17/// will contain different values.
18#[macro_export]
19macro_rules! flow_local {
20    (static $NAME:ident : $t:ty = $e:expr) => {
21        static $NAME: $crate::FlowLocal<$t> = {
22            fn __init() -> $t {
23                $e
24            }
25            fn __key() -> ::std::any::TypeId {
26                struct __A;
27                ::std::any::TypeId::of::<__A>()
28            }
29            $crate::FlowLocal {
30                __init: __init,
31                __key: __key,
32            }
33        };
34    };
35}
36
37/// Am immutable wrapper around a value from a flow local.
38///
39/// This is returned when a flow local is accessed and is internally
40/// reference counted.  Cloning this value is reasonably efficient.
41#[derive(Clone)]
42pub struct FlowBox<T: ?Sized>(Arc<Box<T>>);
43
44pub(crate) type LocalMap = HashMap<TypeId, Box<Opaque>, BuildHasherDefault<IdHasher>>;
45
46pub(crate) trait Opaque: Send + Sync {}
47impl<T: Send + Sync> Opaque for T {}
48
49/// A key for flow-local data stored in the execution context.
50///
51/// This type is generated by the `flow_local!` macro and performs very
52/// similarly to the `thread_local!` macro and `std::thread::FlowLocal` types.
53/// Data associated with a `FlowLocal<T>` is stored inside the current
54/// execution context and the data is destroyed when the execution context
55/// is destroyed.
56///
57/// Flow-local data can migrate between threads and hence requires a `Send`
58/// bound. Additionally, flow-local data also requires the `'static` bound to
59/// ensure it lives long enough. When a key is accessed for the first time the
60/// flow's data is initialized with the provided initialization expression to
61/// the macro.
62pub struct FlowLocal<T> {
63    // "private" fields which have to be public to get around macro hygiene, not
64    // included in the stability story for this type. Can change at any time.
65    #[doc(hidden)]
66    pub __key: fn() -> TypeId,
67    #[doc(hidden)]
68    pub __init: fn() -> T,
69}
70
71impl<T> fmt::Debug for FlowLocal<T> {
72    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
73        write!(f, "FlowLocal")
74    }
75}
76
77pub(crate) struct IdHasher {
78    id: u64,
79}
80
81impl Default for IdHasher {
82    fn default() -> IdHasher {
83        IdHasher { id: 0 }
84    }
85}
86
87impl Hasher for IdHasher {
88    fn write(&mut self, _bytes: &[u8]) {
89        // TODO: need to do something sensible
90        panic!("can only hash u64");
91    }
92
93    fn write_u64(&mut self, u: u64) {
94        self.id = u;
95    }
96
97    fn finish(&self) -> u64 {
98        self.id
99    }
100}
101
102impl<T: Send + 'static> FlowLocal<T> {
103    /// Access this flow-local.
104    ///
105    /// This function will access this flow-local key to retrieve the data
106    /// associated with the current flow and this key. If this is the first time
107    /// this key has been accessed on this flow, then the key will be
108    /// initialized with the initialization expression provided at the time the
109    /// `flow_local!` macro was called.
110    pub fn get(&self) -> FlowBox<T> {
111        let key = (self.__key)();
112
113        if let Some(rv) = ExecutionContext::get_local_value(key) {
114            return unsafe { mem::transmute(rv) };
115        };
116
117        let arc = Arc::new(Box::new((self.__init)()));
118        ExecutionContext::set_local_value(key, unsafe {
119            mem::forget(arc.clone());
120            mem::transmute(arc.clone())
121        });
122        FlowBox(arc)
123    }
124
125    /// Sets a new value for the flow-local.
126    pub fn set(&self, value: T) {
127        let key = (self.__key)();
128        let arc = Arc::new(Box::new(value));
129        ExecutionContext::set_local_value(key, unsafe {
130            mem::forget(arc.clone());
131            mem::transmute(arc.clone())
132        });
133    }
134}
135
136impl<T: fmt::Display + ?Sized> fmt::Display for FlowBox<T> {
137    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
138        fmt::Display::fmt(&**self, f)
139    }
140}
141
142impl<T: fmt::Debug + ?Sized> fmt::Debug for FlowBox<T> {
143    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
144        fmt::Debug::fmt(&**self, f)
145    }
146}
147
148impl<T: ?Sized> fmt::Pointer for FlowBox<T> {
149    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
150        // It's not possible to extract the inner Uniq directly from the FlowBox,
151        // instead we cast it to a *const which aliases the Unique
152        let ptr: *const T = &**self;
153        fmt::Pointer::fmt(&ptr, f)
154    }
155}
156
157impl<T: ?Sized> Deref for FlowBox<T> {
158    type Target = T;
159
160    fn deref(&self) -> &T {
161        &*self.0
162    }
163}