syn_pub_items/
thread.rs

1use std::fmt::{self, Debug};
2
3use self::thread_id::ThreadId;
4
5/// ThreadBound is a Sync-maker and Send-maker that allows accessing a value
6/// of type T only from the original thread on which the ThreadBound was
7/// constructed.
8pub struct ThreadBound<T> {
9    value: T,
10    thread_id: ThreadId,
11}
12
13unsafe impl<T> Sync for ThreadBound<T> {}
14
15// Send bound requires Copy, as otherwise Drop could run in the wrong place.
16unsafe impl<T: Copy> Send for ThreadBound<T> {}
17
18impl<T> ThreadBound<T> {
19    pub fn new(value: T) -> Self {
20        ThreadBound {
21            value: value,
22            thread_id: thread_id::current(),
23        }
24    }
25
26    pub fn get(&self) -> Option<&T> {
27        if thread_id::current() == self.thread_id {
28            Some(&self.value)
29        } else {
30            None
31        }
32    }
33}
34
35impl<T: Debug> Debug for ThreadBound<T> {
36    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
37        match self.get() {
38            Some(value) => Debug::fmt(value, formatter),
39            None => formatter.write_str("unknown"),
40        }
41    }
42}
43
44#[cfg(syn_can_use_thread_id)]
45mod thread_id {
46    use std::thread;
47
48    pub use std::thread::ThreadId;
49
50    pub fn current() -> ThreadId {
51        thread::current().id()
52    }
53}
54
55#[cfg(not(syn_can_use_thread_id))]
56mod thread_id {
57    #[allow(deprecated)]
58    use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
59
60    thread_local! {
61        static THREAD_ID: usize = {
62            #[allow(deprecated)]
63            static NEXT_THREAD_ID: AtomicUsize = ATOMIC_USIZE_INIT;
64
65            // Ordering::Relaxed because our only requirement for the ids is
66            // that they are unique. It is okay for the compiler to rearrange
67            // other memory reads around this fetch. It's still an atomic
68            // fetch_add, so no two threads will be able to read the same value
69            // from it.
70            //
71            // The main thing which these orderings affect is other memory reads
72            // around the atomic read, which for our case are irrelevant as this
73            // atomic guards nothing.
74            NEXT_THREAD_ID.fetch_add(1, Ordering::Relaxed)
75        };
76    }
77
78    pub type ThreadId = usize;
79
80    pub fn current() -> ThreadId {
81        THREAD_ID.with(|id| *id)
82    }
83}