syn/
thread.rs

1use std::fmt::{self, Debug};
2use std::thread::{self, ThreadId};
3
4/// ThreadBound is a Sync-maker and Send-maker that allows accessing a value
5/// of type T only from the original thread on which the ThreadBound was
6/// constructed.
7pub(crate) struct ThreadBound<T> {
8    value: T,
9    thread_id: ThreadId,
10}
11
12unsafe impl<T> Sync for ThreadBound<T> {}
13
14// Send bound requires Copy, as otherwise Drop could run in the wrong place.
15//
16// Today Copy and Drop are mutually exclusive so `T: Copy` implies `T: !Drop`.
17// This impl needs to be revisited if that restriction is relaxed in the future.
18unsafe impl<T: Copy> Send for ThreadBound<T> {}
19
20impl<T> ThreadBound<T> {
21    pub(crate) fn new(value: T) -> Self {
22        ThreadBound {
23            value,
24            thread_id: thread::current().id(),
25        }
26    }
27
28    pub(crate) fn get(&self) -> Option<&T> {
29        if thread::current().id() == self.thread_id {
30            Some(&self.value)
31        } else {
32            None
33        }
34    }
35}
36
37impl<T: Debug> Debug for ThreadBound<T> {
38    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
39        match self.get() {
40            Some(value) => Debug::fmt(value, formatter),
41            None => formatter.write_str("unknown"),
42        }
43    }
44}
45
46// Copy the bytes of T, even if the currently running thread is the "wrong"
47// thread. This is fine as long as the original thread is not simultaneously
48// mutating this value via interior mutability, which would be a data race.
49//
50// Currently `T: Copy` is sufficient to guarantee that T contains no interior
51// mutability, because _all_ interior mutability in Rust is built on
52// std::cell::UnsafeCell, which has no Copy impl. This impl needs to be
53// revisited if that restriction is relaxed in the future.
54impl<T: Copy> Copy for ThreadBound<T> {}
55
56impl<T: Copy> Clone for ThreadBound<T> {
57    fn clone(&self) -> Self {
58        *self
59    }
60}