pub(super) struct UnsafeValueExchanger<V>
{
lock: AtomicBool,
value: UnsafeCell<ManuallyDrop<V>>,
#[cfg(debug_assertions)] has_been_split: Cell<bool>,
}
impl<V> UnsafeValueExchanger<V>
{
const BarrierNotYetReached: bool = false;
#[inline(always)]
pub(super) fn new() -> Self
{
Self
{
lock: AtomicBool::new(UnsafeValueExchanger::<V>::BarrierNotYetReached),
value: UnsafeCell::new(ManuallyDrop::new(unsafe_uninitialized())),
#[cfg(debug_assertions)] has_been_split: Cell::new(false),
}
}
#[inline(always)]
pub(super) fn split(&self) -> (UnsafeValueExchangerReleaser<V>, UnsafeValueExchangerWaiter<V>)
{
#[cfg(debug_assertions)]
{
debug_assert!(!self.has_been_split());
self.has_been_split.set(true);
}
(
UnsafeValueExchangerReleaser
{
parent: self as *const Self as usize,
marker: PhantomData,
waiting_thread: current(),
},
UnsafeValueExchangerWaiter(self),
)
}
#[inline(always)]
fn store_value(&self, value: V)
{
self.debug_assert_has_been_split();
debug_assert!(self.lock_is_not_yet_reached());
unsafe { write(self.value.get(), ManuallyDrop::new(value)) };
self.lock.store(true, Release);
}
#[inline(always)]
fn take_value(&self) -> V
{
debug_assert!(!self.lock_is_not_yet_reached());
let manually_drop = unsafe { &mut * self.value.get() };
unsafe { ManuallyDrop::take(manually_drop) }
}
#[inline(always)]
fn lock_is_not_yet_reached(&self) -> bool
{
self.lock.load(Acquire) == UnsafeValueExchanger::<V>::BarrierNotYetReached
}
#[inline(always)]
fn debug_assert_has_been_split(&self)
{
#[cfg(debug_assertions)]
{
debug_assert!(self.has_been_split())
}
}
#[inline(always)]
#[cfg(debug_assertions)]
fn has_been_split(&self) -> bool
{
self.has_been_split.get()
}
}