at master 2.0 kB view raw
1// SPDX-License-Identifier: Apache-2.0 OR MIT 2 3use std::fmt::{self, Debug}; 4use 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. 9pub(crate) struct ThreadBound<T> { 10 value: T, 11 thread_id: ThreadId, 12} 13 14unsafe 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. 20unsafe impl<T: Copy> Send for ThreadBound<T> {} 21 22impl<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 39impl<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. 56impl<T: Copy> Copy for ThreadBound<T> {} 57 58impl<T: Copy> Clone for ThreadBound<T> { 59 fn clone(&self) -> Self { 60 *self 61 } 62}