use std::collections::VecDeque;
use std::future::poll_fn;
use std::{fmt, panic::UnwindSafe, pin::Pin, task::Context, task::Poll};
use futures_core::{FusedStream, Stream};
use super::cell::{Cell, wake};
use crate::task::LocalWaker;
pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
let shared = Cell::new(Shared {
has_receiver: true,
buffer: VecDeque::new(),
blocked_recv: LocalWaker::new(),
closed: LocalWaker::new(),
});
let sender = Sender {
shared: shared.clone(),
};
let receiver = Receiver { shared };
(sender, receiver)
}
#[derive(Debug)]
struct Shared<T> {
buffer: VecDeque<T>,
blocked_recv: LocalWaker,
closed: LocalWaker,
has_receiver: bool,
}
fn close<T>(shared: &Cell<Shared<T>>) {
let (recv, closed) = {
let shared = shared.get_mut();
shared.has_receiver = false;
(shared.blocked_recv.take_local(), shared.closed.take_local())
};
wake(recv);
wake(closed);
}
#[derive(Debug)]
pub struct Sender<T> {
shared: Cell<Shared<T>>,
}
impl<T> Unpin for Sender<T> {}
impl<T> Sender<T> {
pub fn send(&self, item: T) -> Result<(), SendError<T>> {
let waker = {
let shared = self.shared.get_mut();
if !shared.has_receiver {
return Err(SendError(item)); }
shared.buffer.push_back(item);
shared.blocked_recv.take_local()
};
wake(waker);
Ok(())
}
pub fn close(&self) {
close(&self.shared);
}
pub fn is_closed(&self) -> bool {
self.shared.strong_count() == 1 || !self.shared.get_ref().has_receiver
}
pub fn poll_closed(&self, cx: &mut Context<'_>) -> Poll<()> {
if !self.shared.get_ref().has_receiver {
return Poll::Ready(());
}
LocalWaker::register_in(|| &self.shared.get_ref().closed, cx.waker());
if self.shared.get_ref().has_receiver {
Poll::Pending
} else {
Poll::Ready(())
}
}
pub async fn closed(&self) {
poll_fn(|cx| self.poll_closed(cx)).await;
}
}
impl<T> Clone for Sender<T> {
fn clone(&self) -> Self {
Sender {
shared: self.shared.clone(),
}
}
}
impl<T> Drop for Sender<T> {
fn drop(&mut self) {
let count = self.shared.strong_count();
let waker = {
let shared = self.shared.get_mut();
if shared.has_receiver && count == 2 {
shared.has_receiver = false;
shared.blocked_recv.take_local()
} else {
None
}
};
wake(waker);
}
}
#[derive(Debug)]
pub struct Receiver<T> {
shared: Cell<Shared<T>>,
}
impl<T> Receiver<T> {
pub fn sender(&self) -> Sender<T> {
Sender {
shared: self.shared.clone(),
}
}
pub fn close(&self) {
close(&self.shared);
}
pub fn is_closed(&self) -> bool {
self.shared.strong_count() == 1 || !self.shared.get_ref().has_receiver
}
pub async fn recv(&self) -> Option<T> {
poll_fn(|cx| self.poll_recv(cx)).await
}
pub fn poll_recv(&self, cx: &mut Context<'_>) -> Poll<Option<T>> {
if let Poll::Ready(msg) = self.try_recv() {
return Poll::Ready(msg);
}
LocalWaker::register_in(|| &self.shared.get_ref().blocked_recv, cx.waker());
self.try_recv()
}
fn try_recv(&self) -> Poll<Option<T>> {
let shared = self.shared.get_mut();
if let Some(msg) = shared.buffer.pop_front() {
Poll::Ready(Some(msg))
} else if !shared.has_receiver || self.shared.strong_count() == 1 {
Poll::Ready(None)
} else {
Poll::Pending
}
}
}
impl<T> Unpin for Receiver<T> {}
impl<T> Stream for Receiver<T> {
type Item = T;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
self.poll_recv(cx)
}
}
impl<T> FusedStream for Receiver<T> {
fn is_terminated(&self) -> bool {
self.is_closed() && self.shared.get_ref().buffer.is_empty()
}
}
impl<T> UnwindSafe for Receiver<T> {}
impl<T> Drop for Receiver<T> {
fn drop(&mut self) {
let (buffer, waker) = {
let shared = self.shared.get_mut();
shared.has_receiver = false;
(
std::mem::take(&mut shared.buffer),
shared.closed.take_local(),
)
};
wake(waker);
drop(buffer);
}
}
pub struct SendError<T>(T);
impl<T> std::error::Error for SendError<T> {}
impl<T> fmt::Debug for SendError<T> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_tuple("SendError").field(&"...").finish()
}
}
impl<T> fmt::Display for SendError<T> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(fmt, "send failed because receiver is gone")
}
}
impl<T> SendError<T> {
pub fn into_inner(self) -> T {
self.0
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::task::hooks::{ON_CLONE, hook_waker};
use crate::{future::lazy, future::stream_recv};
#[ntex::test]
async fn test_mpsc() {
let (tx, mut rx) = channel();
assert!(format!("{tx:?}").contains("Sender"));
assert!(format!("{rx:?}").contains("Receiver"));
tx.send("test").unwrap();
assert_eq!(stream_recv(&mut rx).await.unwrap(), "test");
let tx2 = tx.clone();
tx2.send("test2").unwrap();
assert_eq!(stream_recv(&mut rx).await.unwrap(), "test2");
assert_eq!(
lazy(|cx| Pin::new(&mut rx).poll_next(cx)).await,
Poll::Pending
);
drop(tx2);
assert_eq!(
lazy(|cx| Pin::new(&mut rx).poll_next(cx)).await,
Poll::Pending
);
drop(tx);
let (tx, mut rx) = channel::<String>();
tx.close();
assert_eq!(stream_recv(&mut rx).await, None);
let (tx, rx) = channel();
tx.send("test").unwrap();
drop(rx);
assert!(tx.send("test").is_err());
let (tx, _) = channel();
let tx2 = tx.clone();
tx.close();
assert!(tx.send("test").is_err());
assert!(tx2.send("test").is_err());
let err = SendError("test");
assert!(format!("{err:?}").contains("SendError"));
assert!(format!("{err}").contains("send failed because receiver is gone"));
assert_eq!(err.into_inner(), "test");
}
#[ntex::test]
async fn test_close() {
let (tx, rx) = channel::<()>();
assert!(!tx.is_closed());
assert!(!rx.is_closed());
assert!(!rx.is_terminated());
tx.close();
assert!(tx.is_closed());
assert!(rx.is_closed());
assert!(rx.is_terminated());
let (tx, rx) = channel::<()>();
assert_eq!(lazy(|cx| rx.poll_recv(cx)).await, Poll::Pending);
assert!(rx.shared.get_ref().blocked_recv.is_set());
rx.close();
assert!(tx.is_closed());
assert!(!rx.shared.get_ref().blocked_recv.is_set());
assert_eq!(lazy(|cx| rx.poll_recv(cx)).await, Poll::Ready(None));
let (tx, rx) = channel::<()>();
drop(tx);
assert!(rx.is_closed());
assert!(rx.is_terminated());
let tx = rx.sender();
assert!(tx.is_closed());
assert!(rx.is_closed());
assert!(rx.is_terminated());
assert!(tx.send(()).is_err());
assert_eq!(rx.recv().await, None);
}
#[ntex::test]
async fn test_poll_closed() {
let (tx, rx) = channel::<()>();
assert_eq!(lazy(|cx| tx.poll_closed(cx)).await, Poll::Pending);
assert!(tx.shared.get_ref().closed.is_set());
drop(rx);
assert!(!tx.shared.get_ref().closed.is_set());
assert_eq!(lazy(|cx| tx.poll_closed(cx)).await, Poll::Ready(()));
tx.closed().await;
let (tx, rx) = channel::<()>();
assert_eq!(lazy(|cx| tx.poll_closed(cx)).await, Poll::Pending);
rx.close();
assert!(!tx.shared.get_ref().closed.is_set());
tx.closed().await;
let (tx, _rx) = channel::<()>();
let tx2 = tx.clone();
assert_eq!(lazy(|cx| tx2.poll_closed(cx)).await, Poll::Pending);
tx.close();
assert!(!tx.shared.get_ref().closed.is_set());
tx2.closed().await;
}
#[test]
fn single_waiter_wakes_latest_task_only() {
use crate::task::hooks::counted_waker;
let (tx, rx) = channel::<u32>();
let (first, first_waker) = counted_waker();
let (second, second_waker) = counted_waker();
let mut first_cx = Context::from_waker(&first_waker);
let mut second_cx = Context::from_waker(&second_waker);
assert_eq!(rx.poll_recv(&mut first_cx), Poll::Pending);
assert_eq!(rx.poll_recv(&mut second_cx), Poll::Pending);
tx.send(1).unwrap();
tx.send(2).unwrap();
assert_eq!((first.get(), second.get()), (0, 1));
assert_eq!(rx.poll_recv(&mut first_cx), Poll::Ready(Some(1)));
let tx2 = tx.clone();
let (first, first_waker) = counted_waker();
let (second, second_waker) = counted_waker();
let mut first_cx = Context::from_waker(&first_waker);
let mut second_cx = Context::from_waker(&second_waker);
assert_eq!(tx.poll_closed(&mut first_cx), Poll::Pending);
assert_eq!(tx2.poll_closed(&mut second_cx), Poll::Pending);
drop(rx);
assert_eq!((first.get(), second.get()), (0, 1));
assert_eq!(tx.poll_closed(&mut first_cx), Poll::Ready(()));
assert_eq!(tx2.poll_closed(&mut second_cx), Poll::Ready(()));
}
#[test]
fn test_drop_receiver_reentrant_send() {
use std::rc::Rc;
struct Msg(Option<Sender<Msg>>, Rc<std::cell::Cell<usize>>);
impl Drop for Msg {
fn drop(&mut self) {
self.1.set(self.1.get() + 1);
if let Some(tx) = self.0.take() {
assert!(tx.send(Msg(None, self.1.clone())).is_err());
}
}
}
let drops = Rc::new(std::cell::Cell::new(0));
let (tx, rx) = channel();
for _ in 0..4 {
tx.send(Msg(Some(tx.clone()), drops.clone())).unwrap();
}
drop(rx);
assert_eq!(drops.get(), 8);
assert!(tx.is_closed());
}
#[ntex::test]
async fn test_fused_drains_buffer() {
let (tx, mut rx) = channel();
tx.send(1).unwrap();
tx.send(2).unwrap();
drop(tx);
assert!(!rx.is_terminated());
assert_eq!(stream_recv(&mut rx).await, Some(1));
assert_eq!(stream_recv(&mut rx).await, Some(2));
assert!(rx.is_terminated());
assert_eq!(stream_recv(&mut rx).await, None);
let (tx, mut rx) = channel();
tx.send(1).unwrap();
rx.close();
assert!(!rx.is_terminated());
assert_eq!(stream_recv(&mut rx).await, Some(1));
assert!(rx.is_terminated());
}
#[ntex::test]
async fn test_mpsc_recv() {
let (tx, rx) = channel();
tx.send(1).unwrap();
assert_eq!(rx.recv().await, Some(1));
drop(tx);
assert_eq!(rx.recv().await, None);
}
#[test]
fn miri_poll_recv_with_reentrant_clone() {
let (tx, rx) = channel();
let tx2 = tx.clone();
ON_CLONE.set(Some(Box::new(move || tx2.send(1).unwrap())));
let waker = hook_waker();
let mut cx = Context::from_waker(&waker);
assert_eq!(rx.poll_recv(&mut cx), Poll::Ready(Some(1)));
drop(tx);
}
}