pub mod sync {
super::impl_bilock!(sync);
unsafe impl<T: Send> Send for Inner<T> {}
unsafe impl<T: Send> Sync for Inner<T> {}
impl<T: Send> crate::AssertMt for BiLock<T> {}
impl<T: Send> crate::AssertMt for BiLockAcquire<'_, T> {}
impl<T: Send> crate::AssertMt for BiLockGuard<'_, T> {}
}
pub mod unsync {
super::impl_bilock!(unsync);
}
macro_rules! impl_bilock {
($sync:ident) => {
use std::{
fmt::Debug,
future::Future,
ops::{Deref, DerefMut},
pin::Pin,
task::{Context, Poll},
};
crate::cfg_loom! {
use std::cell::UnsafeCell;
}
use crate::$sync::{flag::Flag, shared::Shared, waker_slot::WakerSlot};
pub struct BiLock<T>(Shared<Inner<T>>);
impl<T> Debug for BiLock<T>
where
T: Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("BiLock")
.field("locked", &self.0.locked.get())
.finish()
}
}
impl<T> BiLock<T> {
pub fn new(data: T) -> (Self, Self) {
let inner = Shared::new(Inner {
data: UnsafeCell::new(data),
waiter: WakerSlot::new(),
locked: Flag::new(false),
});
(Self(inner.clone()), Self(inner))
}
pub fn lock(&self) -> BiLockAcquire<'_, T> {
BiLockAcquire { inner: &self.0 }
}
pub fn try_join(self, other: Self) -> Option<T> {
if Shared::ptr_eq(&self.0, &other.0) {
drop(other);
let value = Shared::try_unwrap(self.0)
.map_err(|_| ())
.expect("BiLock is still shared")
.data
.into_inner();
Some(value)
} else {
None
}
}
#[allow(unused)]
pub fn join(self, other: Self) -> T {
if let Some(value) = self.try_join(other) {
value
} else {
#[cold]
fn panic_unrelated() -> ! {
panic!("Unrelated `BiLock` passed to `BiLock::join`.")
}
panic_unrelated()
}
}
}
pub struct BiLockAcquire<'a, T> {
inner: &'a Inner<T>,
}
impl<'a, T> Future for BiLockAcquire<'a, T> {
type Output = BiLockGuard<'a, T>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
if this.inner.locked.swap(true) {
this.inner.waiter.register(cx.waker());
Poll::Pending
} else {
Poll::Ready(BiLockGuard { inner: this.inner })
}
}
}
struct Inner<T: ?Sized> {
locked: Flag,
waiter: WakerSlot,
data: UnsafeCell<T>,
}
pub struct BiLockGuard<'a, T: ?Sized> {
inner: &'a Inner<T>,
}
impl<T: ?Sized> Deref for BiLockGuard<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.inner.data.get() }
}
}
impl<T: ?Sized> DerefMut for BiLockGuard<'_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *self.inner.data.get() }
}
}
impl<T: ?Sized> Drop for BiLockGuard<'_, T> {
fn drop(&mut self) {
self.inner.locked.swap(false);
self.inner.waiter.wake();
}
}
};
}
use impl_bilock;