futures_core/task/
data.rs

1use std::prelude::v1::*;
2
3use std::any::TypeId;
4use std::hash::{BuildHasherDefault, Hasher};
5use std::collections::HashMap;
6
7use task;
8
9/// A macro to create a `static` of type `LocalKey`
10///
11/// This macro is intentionally similar to the `thread_local!`, and creates a
12/// `static` which has a `get_mut` method to access the data on a task.
13///
14/// The data associated with each task local is per-task, so different tasks
15/// will contain different values.
16#[macro_export]
17macro_rules! task_local {
18    (static $NAME:ident: $t:ty = $e:expr) => (
19        static $NAME: $crate::task::LocalKey<$t> = {
20            fn __init() -> $t { $e }
21            fn __key() -> ::std::any::TypeId {
22                struct __A;
23                ::std::any::TypeId::of::<__A>()
24            }
25            $crate::task::LocalKey {
26                __init: __init,
27                __key: __key,
28            }
29        };
30    )
31}
32
33pub struct LocalMap(HashMap<TypeId, Box<Opaque>, BuildHasherDefault<IdHasher>>);
34
35pub fn local_map() -> LocalMap {
36    LocalMap(HashMap::default())
37}
38
39pub trait Opaque: Send {}
40impl<T: Send> Opaque for T {}
41
42/// A key for task-local data stored in a future's task.
43///
44/// This type is generated by the `task_local!` macro and performs very
45/// similarly to the `thread_local!` macro and `std::thread::LocalKey` types.
46/// Data associated with a `LocalKey<T>` is stored inside of a future's task,
47/// and the data is destroyed when the future is completed and the task is
48/// destroyed.
49///
50/// Task-local data can migrate between threads and hence requires a `Send`
51/// bound. Additionally, task-local data also requires the `'static` bound to
52/// ensure it lives long enough. When a key is accessed for the first time the
53/// task's data is initialized with the provided initialization expression to
54/// the macro.
55#[derive(Debug)]
56pub struct LocalKey<T> {
57    // "private" fields which have to be public to get around macro hygiene, not
58    // included in the stability story for this type. Can change at any time.
59    #[doc(hidden)]
60    pub __key: fn() -> TypeId,
61    #[doc(hidden)]
62    pub __init: fn() -> T,
63}
64
65pub struct IdHasher {
66    id: u64,
67}
68
69impl Default for IdHasher {
70    fn default() -> IdHasher {
71        IdHasher { id: 0 }
72    }
73}
74
75impl Hasher for IdHasher {
76    fn write(&mut self, _bytes: &[u8]) {
77        // TODO: need to do something sensible
78        panic!("can only hash u64");
79    }
80
81    fn write_u64(&mut self, u: u64) {
82        self.id = u;
83    }
84
85    fn finish(&self) -> u64 {
86        self.id
87    }
88}
89
90impl<T: Send + 'static> LocalKey<T> {
91    /// Access this task-local key.
92    ///
93    /// This function will access this task-local key to retrieve the data
94    /// associated with the current task and this key. If this is the first time
95    /// this key has been accessed on this task, then the key will be
96    /// initialized with the initialization expression provided at the time the
97    /// `task_local!` macro was called.
98    pub fn get_mut<'a>(&'static self, cx: &'a mut task::Context) -> &'a mut T {
99        let key = (self.__key)();
100        let data = &mut cx.map.inner.0;
101        let entry: &mut Box<Opaque> = data.entry(key).or_insert_with(|| {
102            Box::new((self.__init)())
103        });
104        unsafe { &mut *(&mut **entry as *mut Opaque as *mut T) }
105    }
106}