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