#[cfg(test)]
mod tests;
use core::fmt;
use futures::task::AtomicWaker;
use futures::{ready, Future};
use std::cell::UnsafeCell;
use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::ops::{Deref, DerefMut};
use std::pin::Pin;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::task::{Context, Poll};
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
pub fn bilock<T>(val: T) -> (BiLock<T>, BiLock<T>) {
let inner = Arc::new(Inner {
state: AtomicBool::new(false),
waker: AtomicWaker::default(),
value: UnsafeCell::new(val),
});
(
BiLock {
inner: inner.clone(),
},
BiLock { inner },
)
}
#[derive(Debug)]
pub struct BiLock<T> {
inner: Arc<Inner<T>>,
}
#[derive(Debug)]
struct Inner<T> {
state: AtomicBool,
waker: AtomicWaker,
value: UnsafeCell<T>,
}
unsafe impl<T: Send> Send for Inner<T> {}
unsafe impl<T: Send> Sync for Inner<T> {}
impl<T> BiLock<T> {
pub fn same_bilock(&self, other: &Self) -> bool {
Arc::ptr_eq(&self.inner, &other.inner)
}
pub fn lock(&self) -> LockFuture<'_, T> {
LockFuture { bilock: self }
}
pub fn poll_lock(&self, cx: &mut Context<'_>) -> Poll<BiLockGuard<'_, T>> {
if self.inner.state.swap(true, Ordering::SeqCst) {
self.inner.waker.register(cx.waker());
if self.inner.state.swap(true, Ordering::SeqCst) {
Poll::Pending
} else {
Poll::Ready(BiLockGuard { bilock: self })
}
} else {
Poll::Ready(BiLockGuard { bilock: self })
}
}
fn unlock(&self) {
if self.inner.state.swap(false, Ordering::SeqCst) {
self.inner.waker.wake();
} else {
}
}
pub fn reunite(self, other: BiLock<T>) -> Result<T, ReuniteError<T>>
where
T: Unpin,
{
if Arc::ptr_eq(&self.inner, &other.inner) {
drop(other);
let inner = Arc::try_unwrap(self.inner)
.ok()
.expect("Failed to unwrap Arc");
Ok(inner.value.into_inner())
} else {
Err(ReuniteError(self, other))
}
}
}
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct LockFuture<'l, T> {
bilock: &'l BiLock<T>,
}
impl<T> Unpin for LockFuture<'_, T> {}
impl<'l, T> Future for LockFuture<'l, T> {
type Output = BiLockGuard<'l, T>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
self.get_mut().bilock.poll_lock(cx)
}
}
pub struct BiLockGuard<'l, T> {
bilock: &'l BiLock<T>,
}
impl<'l, T> Drop for BiLockGuard<'l, T> {
fn drop(&mut self) {
self.bilock.unlock();
}
}
impl<T> Deref for BiLockGuard<'_, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.bilock.inner.value.get() }
}
}
impl<T: Unpin> DerefMut for BiLockGuard<'_, T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.bilock.inner.value.get() }
}
}
pub struct ReuniteError<T>(pub BiLock<T>, pub BiLock<T>);
impl<T> Debug for ReuniteError<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_tuple("ReuniteError").finish()
}
}
impl<T> Display for ReuniteError<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Attempted to reunite two BiLocks that don't form a pair")
}
}
impl<T> Error for ReuniteError<T> {}
impl<T> AsyncRead for BiLock<T>
where
T: AsyncRead + Unpin,
{
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut ReadBuf<'_>,
) -> Poll<std::io::Result<()>> {
let mut guard = ready!(self.get_mut().poll_lock(cx));
Pin::new(guard.deref_mut()).poll_read(cx, buf)
}
}
impl<T> AsyncWrite for BiLock<T>
where
T: AsyncWrite + Unpin,
{
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<Result<usize, std::io::Error>> {
let mut guard = ready!(self.get_mut().poll_lock(cx));
Pin::new(guard.deref_mut()).poll_write(cx, buf)
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), std::io::Error>> {
let mut guard = ready!(self.get_mut().poll_lock(cx));
Pin::new(guard.deref_mut()).poll_flush(cx)
}
fn poll_shutdown(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Result<(), std::io::Error>> {
let mut guard = ready!(self.get_mut().poll_lock(cx));
Pin::new(guard.deref_mut()).poll_flush(cx)
}
}