use core::task::{Waker, Context, Poll};
use core::future::Future;
use core::pin::Pin;
use alloc::boxed::Box;
use alloc::sync::Arc;
use crate::slot::Slot;
struct OneShot<T> {
payload: Slot<T>,
consumer_waker: Slot<Waker>,
}
pub struct Sender<T> {
inner: Arc<OneShot<T>>,
}
pub struct Receiver<T> {
inner: Arc<OneShot<T>>,
}
pub fn new<T>() -> (Sender<T>, Receiver<T>) {
let inner = OneShot {
payload: Slot::NONE,
consumer_waker: Slot::NONE,
};
let inner = Arc::new(inner);
let sender = Sender {
inner: inner.clone(),
};
let receiver = Receiver {
inner: inner.clone(),
};
(sender, receiver)
}
impl<T> Sender<T> {
pub fn send(self, item: Box<T>) {
self.inner.payload.insert(item);
if let Some(waker_box) = self.inner.consumer_waker.try_take(false) {
waker_box.wake_by_ref();
}
}
}
#[cfg(feature = "blocking")]
impl<T> Receiver<T> {
pub fn recv_blocking(self) -> T {
*crate::block_on(self)
}
}
impl<T> Future for Receiver<T> {
type Output = Box<T>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if let Some(item) = self.inner.payload.try_take(false) {
return Poll::Ready(item);
}
let waker = Box::new(cx.waker().clone());
self.inner.consumer_waker.insert(waker);
match self.inner.payload.try_take(false) {
Some(item) => Poll::Ready(item),
None => Poll::Pending,
}
}
}