use core::{
cell::{Cell, UnsafeCell},
fmt,
future::Future,
mem::MaybeUninit,
pin::Pin,
task::{Context, Poll, Waker},
};
use std::rc::Rc;
use futures_core::future::FusedFuture;
use crate::cell::LocalCell;
struct Inner<T> {
value: UnsafeCell<MaybeUninit<T>>,
value_present: Cell<bool>,
sender_dropped: Cell<bool>,
receiver_dropped: Cell<bool>,
recv_waker: LocalCell<Option<Waker>>,
}
impl<T> Inner<T> {
#[inline]
fn register_recv_waker(&self, waker: &Waker) {
if self.receiver_dropped.get() {
return;
}
let waker = waker.clone();
let replaced = self.recv_waker.borrow_mut().replace(waker);
drop(replaced);
}
#[inline(always)]
fn wake_receiver(&self) {
let waker = self.recv_waker.borrow_mut().take();
if let Some(waker) = waker {
waker.wake();
}
}
#[inline(always)]
fn clear_recv_waker(&self) {
let taken = self.recv_waker.borrow_mut().take();
drop(taken);
}
#[inline(always)]
fn drop_value(&self) {
if self.value_present.replace(false) {
unsafe { (*self.value.get()).assume_init_drop() };
}
}
}
impl<T> Drop for Inner<T> {
#[inline(always)]
fn drop(&mut self) {
self.drop_value();
}
}
pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
let inner = Rc::new(Inner {
value: UnsafeCell::new(MaybeUninit::uninit()),
value_present: Cell::new(false),
sender_dropped: Cell::new(false),
receiver_dropped: Cell::new(false),
recv_waker: LocalCell::new(None),
});
(
Sender {
inner: inner.clone(),
},
Receiver { inner, done: false },
)
}
pub struct Sender<T> {
inner: Rc<Inner<T>>,
}
impl<T> Sender<T> {
#[inline]
pub fn send(self, value: T) -> Result<(), T> {
if self.inner.receiver_dropped.get() {
return Err(value);
}
unsafe { (*self.inner.value.get()).write(value) };
self.inner.value_present.set(true);
self.inner.wake_receiver();
Ok(())
}
#[inline(always)]
pub fn is_closed(&self) -> bool {
self.inner.receiver_dropped.get()
}
}
impl<T> Drop for Sender<T> {
#[inline(always)]
fn drop(&mut self) {
self.inner.sender_dropped.set(true);
if !self.inner.value_present.get() {
self.inner.wake_receiver();
}
}
}
pub struct Receiver<T> {
inner: Rc<Inner<T>>,
done: bool,
}
impl<T> Receiver<T> {
#[inline]
pub fn try_recv(&mut self) -> Result<Option<T>, Canceled> {
if let Some(value) = self.take_value() {
return Ok(Some(value));
}
if !self.done && self.inner.sender_dropped.get() {
self.done = true;
return Err(Canceled(()));
}
Ok(None)
}
#[inline]
fn take_value(&mut self) -> Option<T> {
if self.done {
return None;
}
if self.inner.value_present.replace(false) {
let value = unsafe { (*self.inner.value.get()).assume_init_read() };
self.done = true;
return Some(value);
}
None
}
#[inline]
pub fn try_iter(&mut self) -> TryIter<'_, T> {
TryIter(self)
}
#[inline(always)]
pub fn is_closed(&self) -> bool {
self.inner.sender_dropped.get()
}
}
impl<T> Future for Receiver<T> {
type Output = Result<T, Canceled>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
if this.done {
return Poll::Pending;
}
if this.inner.value_present.replace(false) {
let value = unsafe { (*this.inner.value.get()).assume_init_read() };
this.done = true;
return Poll::Ready(Ok(value));
}
if this.inner.sender_dropped.get() {
this.done = true;
return Poll::Ready(Err(Canceled(())));
}
this.inner.register_recv_waker(cx.waker());
if this.inner.value_present.replace(false) {
let value = unsafe { (*this.inner.value.get()).assume_init_read() };
this.done = true;
return Poll::Ready(Ok(value));
}
if this.inner.sender_dropped.get() {
this.done = true;
return Poll::Ready(Err(Canceled(())));
}
Poll::Pending
}
}
impl<T> FusedFuture for Receiver<T> {
#[inline(always)]
fn is_terminated(&self) -> bool {
self.done
}
}
impl<T> Drop for Receiver<T> {
fn drop(&mut self) {
self.inner.receiver_dropped.set(true);
self.inner.clear_recv_waker();
self.inner.drop_value();
}
}
pub struct TryIter<'a, T>(&'a mut Receiver<T>);
impl<T> Iterator for TryIter<'_, T> {
type Item = T;
#[inline]
fn next(&mut self) -> Option<T> {
self.0.take_value()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Canceled(());
impl fmt::Display for Canceled {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("oneshot sender dropped without sending a value")
}
}
impl core::error::Error for Canceled {}
#[cfg(all(test, feature = "std"))]
mod tests;