1 | use std::fmt::{self, Debug}; |
2 | use 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. |
7 | pub(crate) struct ThreadBound<T> { |
8 | value: T, |
9 | thread_id: ThreadId, |
10 | } |
11 | |
12 | unsafe 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. |
18 | unsafe impl<T: Copy> Send for ThreadBound<T> {} |
19 | |
20 | impl<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 | |
37 | impl<T: Debug> Debug for ThreadBound<T> { |
38 | fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
39 | match self.get() { |
40 | Some(value: &T) => Debug::fmt(self:value, f:formatter), |
41 | None => formatter.write_str(data:"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. |
54 | impl<T: Copy> Copy for ThreadBound<T> {} |
55 | |
56 | impl<T: Copy> Clone for ThreadBound<T> { |
57 | fn clone(&self) -> Self { |
58 | *self |
59 | } |
60 | } |
61 | |