use super::wait_queue::WaitQueue;
use std::cell::UnsafeCell;
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::task::{Context, Poll};
#[repr(align(64))]
struct Inner<T> {
value: UnsafeCell<Option<T>>,
sent: AtomicBool,
sender_dropped: AtomicBool,
receiver_dropped: AtomicBool,
wait: WaitQueue,
}
unsafe impl<T: Send> Send for Inner<T> {}
unsafe impl<T: Send> Sync for Inner<T> {}
#[must_use]
#[inline]
pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
let inner = Arc::new(Inner {
value: UnsafeCell::new(None),
sent: AtomicBool::new(false),
sender_dropped: AtomicBool::new(false),
receiver_dropped: AtomicBool::new(false),
wait: WaitQueue::new(),
});
(
Sender {
inner: inner.clone(),
},
Receiver { inner },
)
}
#[repr(align(64))]
pub struct Sender<T> {
inner: Arc<Inner<T>>,
}
impl<T> Sender<T> {
#[inline(always)]
pub fn send(self, value: T) -> Result<(), T> {
if self.inner.receiver_dropped.load(Ordering::Acquire) {
return Err(value);
}
unsafe {
*self.inner.value.get() = Some(value);
}
self.inner.sent.store(true, Ordering::Release);
self.inner.wait.wake_all();
Ok(())
}
#[must_use]
#[inline(always)]
pub fn is_closed(&self) -> bool {
self.inner.receiver_dropped.load(Ordering::Acquire)
}
}
impl<T> Drop for Sender<T> {
#[inline(always)]
fn drop(&mut self) {
self.inner.sender_dropped.store(true, Ordering::Release);
self.inner.wait.wake_all();
}
}
#[repr(align(64))]
pub struct Receiver<T> {
inner: Arc<Inner<T>>,
}
impl<T> Drop for Receiver<T> {
#[inline(always)]
fn drop(&mut self) {
self.inner.receiver_dropped.store(true, Ordering::Release);
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(align(64))]
pub struct RecvError;
impl std::fmt::Display for RecvError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("sender dropped without sending a value")
}
}
impl std::error::Error for RecvError {}
impl<T> Future for Receiver<T> {
type Output = Result<T, RecvError>;
#[inline(always)]
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if let Some(result) = self.try_take() {
return Poll::Ready(result);
}
let token = self.inner.wait.register(cx.waker());
if let Some(result) = self.try_take() {
self.inner.wait.cancel(token);
return Poll::Ready(result);
}
Poll::Pending
}
}
impl<T> Receiver<T> {
#[inline(always)]
fn try_take(&self) -> Option<Result<T, RecvError>> {
if self.inner.sent.load(Ordering::Acquire) {
let value = unsafe { (*self.inner.value.get()).take() };
return Some(value.ok_or(RecvError));
}
if self.inner.sender_dropped.load(Ordering::Acquire) {
if self.inner.sent.load(Ordering::Acquire) {
let value = unsafe { (*self.inner.value.get()).take() };
return Some(value.ok_or(RecvError));
}
return Some(Err(RecvError));
}
None
}
}