blob: ff47e4af4d780251dac5047432c12cd9056b951d [file] [log] [blame]
David Tolnay32874802018-11-11 08:52:19 -08001use std::fmt::{self, Debug};
2
David Tolnay88658612018-11-11 09:52:11 -08003use self::thread_id::ThreadId;
David Tolnay32874802018-11-11 08:52:19 -08004
David Tolnay88658612018-11-11 09:52:11 -08005/// 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,
David Tolnay32874802018-11-11 08:52:19 -080011}
12
David Tolnay88658612018-11-11 09:52:11 -080013unsafe 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 }
David Tolnay32874802018-11-11 08:52:19 -080024 }
25
David Tolnay88658612018-11-11 09:52:11 -080026 pub fn get(&self) -> Option<&T> {
27 if thread_id::current() == self.thread_id {
David Tolnay32874802018-11-11 08:52:19 -080028 Some(&self.value)
David Tolnay88658612018-11-11 09:52:11 -080029 } else {
30 None
David Tolnay32874802018-11-11 08:52:19 -080031 }
32 }
33}
34
David Tolnay32874802018-11-11 08:52:19 -080035impl<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}
David Tolnay88658612018-11-11 09:52:11 -080043
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 {
David Tolnaye41c4412019-02-28 23:25:18 -080057 #[allow(deprecated)]
David Tolnay88658612018-11-11 09:52:11 -080058 use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
59
60 thread_local! {
61 static THREAD_ID: usize = {
David Tolnaye41c4412019-02-28 23:25:18 -080062 #[allow(deprecated)]
David Tolnay88658612018-11-11 09:52:11 -080063 static NEXT_THREAD_ID: AtomicUsize = ATOMIC_USIZE_INIT;
David Tolnayd1f57cd2018-11-11 10:28:50 -080064
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.
David Tolnay88658612018-11-11 09:52:11 -080074 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}