use core::{
cell::Cell,
pin::Pin,
task::{Context, Poll},
};
use std::rc::Rc;
use futures_core::stream::{FusedStream, Stream};
use super::{
chan::Chan,
error::{TryRecvError, TrySendError},
recv::Recv,
send::Send,
};
pub struct Sender<T> {
chan: Rc<Chan<T>>,
}
impl<T> Sender<T> {
pub(super) fn new(chan: Rc<Chan<T>>) -> Self {
Self { chan }
}
#[inline(always)]
pub fn try_send(&self, item: T) -> Result<(), TrySendError<T>> {
if !self.chan.receiver_alive() {
return Err(TrySendError::Closed(item));
}
match self.chan.try_push(item) {
Ok(()) => {
self.chan.wake_receivers();
Ok(())
}
Err(item) => Err(TrySendError::Full(item)),
}
}
pub fn capacity(&self) -> Option<usize> {
self.chan.cap()
}
pub fn len(&self) -> usize {
self.chan.len()
}
pub fn is_empty(&self) -> bool {
self.chan.is_empty()
}
pub fn is_full(&self) -> bool {
self.chan.is_full()
}
pub fn is_closed(&self) -> bool {
!self.chan.receiver_alive()
}
#[inline(always)]
pub fn send(&self, item: T) -> Send<'_, T> {
Send::new(self, item)
}
pub(super) fn chan(&self) -> &Chan<T> {
&self.chan
}
}
impl<T> Clone for Sender<T> {
fn clone(&self) -> Self {
self.chan.incr_senders();
Self {
chan: self.chan.clone(),
}
}
}
impl<T> Drop for Sender<T> {
fn drop(&mut self) {
if self.chan.decr_senders() == 1 {
self.chan.wake_receivers();
}
}
}
pub struct Receiver<T> {
chan: Rc<Chan<T>>,
stream_waker_id: Cell<Option<u64>>,
}
impl<T> Receiver<T> {
pub(super) fn new(chan: Rc<Chan<T>>) -> Self {
Self {
chan,
stream_waker_id: Cell::new(None),
}
}
#[inline(always)]
pub fn try_recv(&self) -> Result<T, TryRecvError> {
match self.chan.try_take() {
Some(item) => Ok(item),
None if self.chan.senders() == 0 => Err(TryRecvError::Disconnected),
None => Err(TryRecvError::Empty),
}
}
#[inline(always)]
pub fn recv(&self) -> Recv<'_, T> {
Recv::new(self)
}
#[inline]
pub fn try_iter(&self) -> TryIter<'_, T> {
TryIter(self)
}
#[inline]
pub(super) fn poll_recv(
&self,
cx: &mut Context<'_>,
waker_id: &Cell<Option<u64>>,
) -> Poll<Option<T>> {
let chan = &self.chan;
if let Some(old) = waker_id.take() {
chan.remove_recv_waker(old);
}
if let Some(item) = chan.try_take() {
return Poll::Ready(Some(item));
}
if chan.senders() == 0 {
return Poll::Ready(None);
}
let id = chan.add_recv_waker(cx.waker());
waker_id.set(Some(id));
if let Some(item) = chan.try_take() {
return Poll::Ready(Some(item));
}
if chan.senders() == 0 {
if let Some(id) = waker_id.take() {
chan.remove_recv_waker(id);
}
return Poll::Ready(None);
}
Poll::Pending
}
pub(super) fn chan(&self) -> &Chan<T> {
&self.chan
}
pub fn len(&self) -> usize {
self.chan.len()
}
pub fn is_empty(&self) -> bool {
self.chan.is_empty()
}
}
impl<T> Clone for Receiver<T> {
fn clone(&self) -> Self {
self.chan.incr_receivers();
Self {
chan: self.chan.clone(),
stream_waker_id: Cell::new(None),
}
}
}
impl<T> Drop for Receiver<T> {
fn drop(&mut self) {
let was_last = self.chan.decr_receivers() == 1;
if !was_last {
if let Some(id) = self.stream_waker_id.take() {
self.chan.remove_recv_waker(id);
}
return;
}
struct Cleanup<'a, T> {
chan: &'a Chan<T>,
stream_id: Option<u64>,
}
impl<T> Drop for Cleanup<'_, T> {
fn drop(&mut self) {
struct RemoveStream<'a, T> {
chan: &'a Chan<T>,
id: Option<u64>,
}
impl<T> Drop for RemoveStream<'_, T> {
fn drop(&mut self) {
if let Some(id) = self.id.take() {
self.chan.remove_recv_waker(id);
}
}
}
let _remove = RemoveStream {
chan: self.chan,
id: self.stream_id.take(),
};
self.chan.drain();
}
}
let cleanup = Cleanup {
chan: &self.chan,
stream_id: self.stream_waker_id.take(),
};
self.chan.wake_senders();
drop(cleanup);
}
}
impl<T> Stream for Receiver<T> {
type Item = T;
#[inline]
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<T>> {
let this = self.get_mut();
this.poll_recv(cx, &this.stream_waker_id)
}
}
impl<T> FusedStream for Receiver<T> {
#[inline]
fn is_terminated(&self) -> bool {
self.stream_waker_id.get().is_none() && self.chan.senders() == 0 && self.chan.is_empty()
}
}
pub struct TryIter<'a, T>(&'a Receiver<T>);
impl<T> Iterator for TryIter<'_, T> {
type Item = T;
#[inline]
fn next(&mut self) -> Option<T> {
self.0.try_recv().ok()
}
}