#![allow(unsafe_code)]
use core::cell::{Cell, UnsafeCell};
use core::fmt;
use core::future::Future;
use core::pin::Pin;
use core::task::{Context, Poll, Waker};
use crate::mem::BlockRc as Rc;
pub use crate::sync::oneshot::error;
use crate::sync::oneshot::error::{RecvError, TryRecvError};
const VALUE_SENT: u8 = 0b001;
const RX_CLOSED: u8 = 0b010;
const TX_DROPPED: u8 = 0b100;
struct Inner<T> {
state: Cell<u8>,
value: UnsafeCell<Option<T>>,
rx_waker: Cell<Option<Waker>>,
tx_waker: Cell<Option<Waker>>,
}
impl<T> Inner<T> {
fn has(&self, bit: u8) -> bool {
self.state.get() & bit != 0
}
fn set(&self, bit: u8) {
self.state.set(self.state.get() | bit);
}
fn put(&self, value: T) {
unsafe { *self.value.get() = Some(value) };
}
fn take(&self) -> Option<T> {
unsafe { (*self.value.get()).take() }
}
}
#[inline]
fn register(slot: &Cell<Option<Waker>>, waker: &Waker) {
match slot.take() {
Some(old) if old.will_wake(waker) => slot.set(Some(old)),
old => {
slot.set(Some(waker.clone()));
drop(old);
}
}
}
#[inline]
fn wake(slot: &Cell<Option<Waker>>) {
if let Some(waker) = slot.take() {
waker.wake();
}
}
pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
let inner = Rc::new(Inner {
state: Cell::new(0),
value: UnsafeCell::new(None),
rx_waker: Cell::new(None),
tx_waker: Cell::new(None),
});
(
Sender {
inner: Some(Rc::clone(&inner)),
},
Receiver { inner: Some(inner) },
)
}
pub struct Sender<T> {
inner: Option<Rc<Inner<T>>>,
}
impl<T> Sender<T> {
pub fn send(mut self, value: T) -> Result<(), T> {
let Some(inner) = self.inner.take() else {
return Err(value);
};
if inner.has(RX_CLOSED) {
inner.set(TX_DROPPED);
return Err(value);
}
inner.put(value);
inner.set(VALUE_SENT | TX_DROPPED);
wake(&inner.rx_waker);
Ok(())
}
pub async fn closed(&mut self) {
core::future::poll_fn(|cx| self.poll_closed(cx)).await;
}
pub fn is_closed(&self) -> bool {
self.inner.as_ref().is_none_or(|inner| inner.has(RX_CLOSED))
}
pub fn poll_closed(&mut self, cx: &mut Context<'_>) -> Poll<()> {
let Some(inner) = self.inner.as_ref() else {
return Poll::Ready(());
};
if inner.has(RX_CLOSED) {
return Poll::Ready(());
}
register(&inner.tx_waker, cx.waker());
Poll::Pending
}
}
impl<T> Drop for Sender<T> {
fn drop(&mut self) {
let Some(inner) = self.inner.as_ref() else {
return;
};
inner.set(TX_DROPPED);
wake(&inner.rx_waker);
drop(inner.tx_waker.take());
}
}
impl<T> fmt::Debug for Sender<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Sender")
.field("is_closed", &self.is_closed())
.finish()
}
}
pub struct Receiver<T> {
inner: Option<Rc<Inner<T>>>,
}
impl<T> Receiver<T> {
pub fn close(&mut self) {
let Some(inner) = self.inner.as_ref() else {
return;
};
inner.set(RX_CLOSED);
wake(&inner.tx_waker);
}
pub fn is_terminated(&self) -> bool {
self.inner.is_none()
}
pub fn is_empty(&self) -> bool {
self.inner
.as_ref()
.is_none_or(|inner| !inner.has(VALUE_SENT))
}
pub fn try_recv(&mut self) -> Result<T, TryRecvError> {
let Some(inner) = self.inner.as_ref() else {
return Err(TryRecvError::Closed);
};
if let Some(value) = inner.take() {
self.inner = None;
return Ok(value);
}
if inner.has(RX_CLOSED | TX_DROPPED) {
self.inner = None;
return Err(TryRecvError::Closed);
}
Err(TryRecvError::Empty)
}
}
impl<T> Drop for Receiver<T> {
fn drop(&mut self) {
let Some(inner) = self.inner.as_ref() else {
return;
};
inner.set(RX_CLOSED);
wake(&inner.tx_waker);
drop(inner.rx_waker.take());
drop(inner.take());
}
}
impl<T> Future for Receiver<T> {
type Output = Result<T, RecvError>;
#[expect(
clippy::panic,
reason = "polled after it completed, which the `Future` contract rules out"
)]
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
let Some(inner) = this.inner.as_ref() else {
panic!("called after complete");
};
if !inner.has(VALUE_SENT | RX_CLOSED | TX_DROPPED) {
register(&inner.rx_waker, cx.waker());
return Poll::Pending;
}
if crate::coop::exhausted(cx.waker()) {
return Poll::Pending;
}
let done = inner.take().ok_or(RecvError(()));
this.inner = None;
crate::coop::spent_one();
Poll::Ready(done)
}
}
impl<T> fmt::Debug for Receiver<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Receiver")
.field("is_terminated", &self.is_terminated())
.field("is_empty", &self.is_empty())
.finish()
}
}