1*69942c0aSMiguel Ojeda // SPDX-License-Identifier: Apache-2.0 OR MIT 2*69942c0aSMiguel Ojeda 3808c999fSMiguel Ojeda use std::fmt::{self, Debug}; 4808c999fSMiguel Ojeda use std::thread::{self, ThreadId}; 5808c999fSMiguel Ojeda 6808c999fSMiguel Ojeda /// ThreadBound is a Sync-maker and Send-maker that allows accessing a value 7808c999fSMiguel Ojeda /// of type T only from the original thread on which the ThreadBound was 8808c999fSMiguel Ojeda /// constructed. 9808c999fSMiguel Ojeda pub(crate) struct ThreadBound<T> { 10808c999fSMiguel Ojeda value: T, 11808c999fSMiguel Ojeda thread_id: ThreadId, 12808c999fSMiguel Ojeda } 13808c999fSMiguel Ojeda 14808c999fSMiguel Ojeda unsafe impl<T> Sync for ThreadBound<T> {} 15808c999fSMiguel Ojeda 16808c999fSMiguel Ojeda // Send bound requires Copy, as otherwise Drop could run in the wrong place. 17808c999fSMiguel Ojeda // 18808c999fSMiguel Ojeda // Today Copy and Drop are mutually exclusive so `T: Copy` implies `T: !Drop`. 19808c999fSMiguel Ojeda // This impl needs to be revisited if that restriction is relaxed in the future. 20808c999fSMiguel Ojeda unsafe impl<T: Copy> Send for ThreadBound<T> {} 21808c999fSMiguel Ojeda 22808c999fSMiguel Ojeda impl<T> ThreadBound<T> { new(value: T) -> Self23808c999fSMiguel Ojeda pub(crate) fn new(value: T) -> Self { 24808c999fSMiguel Ojeda ThreadBound { 25808c999fSMiguel Ojeda value, 26808c999fSMiguel Ojeda thread_id: thread::current().id(), 27808c999fSMiguel Ojeda } 28808c999fSMiguel Ojeda } 29808c999fSMiguel Ojeda get(&self) -> Option<&T>30808c999fSMiguel Ojeda pub(crate) fn get(&self) -> Option<&T> { 31808c999fSMiguel Ojeda if thread::current().id() == self.thread_id { 32808c999fSMiguel Ojeda Some(&self.value) 33808c999fSMiguel Ojeda } else { 34808c999fSMiguel Ojeda None 35808c999fSMiguel Ojeda } 36808c999fSMiguel Ojeda } 37808c999fSMiguel Ojeda } 38808c999fSMiguel Ojeda 39808c999fSMiguel Ojeda impl<T: Debug> Debug for ThreadBound<T> { fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result40808c999fSMiguel Ojeda fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 41808c999fSMiguel Ojeda match self.get() { 42808c999fSMiguel Ojeda Some(value) => Debug::fmt(value, formatter), 43808c999fSMiguel Ojeda None => formatter.write_str("unknown"), 44808c999fSMiguel Ojeda } 45808c999fSMiguel Ojeda } 46808c999fSMiguel Ojeda } 47808c999fSMiguel Ojeda 48808c999fSMiguel Ojeda // Copy the bytes of T, even if the currently running thread is the "wrong" 49808c999fSMiguel Ojeda // thread. This is fine as long as the original thread is not simultaneously 50808c999fSMiguel Ojeda // mutating this value via interior mutability, which would be a data race. 51808c999fSMiguel Ojeda // 52808c999fSMiguel Ojeda // Currently `T: Copy` is sufficient to guarantee that T contains no interior 53808c999fSMiguel Ojeda // mutability, because _all_ interior mutability in Rust is built on 54808c999fSMiguel Ojeda // std::cell::UnsafeCell, which has no Copy impl. This impl needs to be 55808c999fSMiguel Ojeda // revisited if that restriction is relaxed in the future. 56808c999fSMiguel Ojeda impl<T: Copy> Copy for ThreadBound<T> {} 57808c999fSMiguel Ojeda 58808c999fSMiguel Ojeda impl<T: Copy> Clone for ThreadBound<T> { clone(&self) -> Self59808c999fSMiguel Ojeda fn clone(&self) -> Self { 60808c999fSMiguel Ojeda *self 61808c999fSMiguel Ojeda } 62808c999fSMiguel Ojeda } 63