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}
61