use core::{
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> {
#[inline(always)]
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() || self.chan.is_closed() {
return Err(TrySendError::Closed(item));
}
match self.chan.try_push(item) {
Ok(()) => {
self.chan.wake_receiver();
Ok(())
}
Err(item) => Err(TrySendError::Full(item)),
}
}
#[inline(always)]
pub fn capacity(&self) -> Option<usize> {
self.chan.cap()
}
#[inline(always)]
pub fn len(&self) -> usize {
self.chan.len()
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.chan.is_empty()
}
#[inline(always)]
pub fn is_full(&self) -> bool {
self.chan.is_full()
}
#[inline(always)]
pub fn is_closed(&self) -> bool {
!self.chan.receiver_alive() || self.chan.is_closed()
}
#[inline(always)]
pub fn close(&self) -> bool {
if self.is_closed() {
return false;
}
self.chan.close();
true
}
#[inline(always)]
pub fn send(&self, item: T) -> Send<'_, T> {
Send::new(self, item)
}
#[inline(always)]
pub(super) fn chan(&self) -> &Chan<T> {
&self.chan
}
}
impl<T> Clone for Sender<T> {
#[inline]
fn clone(&self) -> Self {
self.chan.incr_senders();
Self {
chan: self.chan.clone(),
}
}
}
impl<T> Drop for Sender<T> {
#[inline]
fn drop(&mut self) {
if self.chan.decr_senders() == 1 {
self.chan.wake_receiver();
}
}
}
pub struct Receiver<T> {
chan: Rc<Chan<T>>,
}
impl<T> Receiver<T> {
#[inline(always)]
pub(super) fn new(chan: Rc<Chan<T>>) -> Self {
Self { chan }
}
#[inline(always)]
pub fn try_recv(&mut self) -> Result<T, TryRecvError> {
match self.chan.pop() {
Some(item) => {
self.chan.wake_senders();
Ok(item)
}
None if self.chan.senders() == 0 || self.chan.is_closed() => Err(TryRecvError::Disconnected),
None => Err(TryRecvError::Empty),
}
}
#[inline(always)]
pub fn recv(&mut self) -> Recv<'_, T> {
Recv::new(self)
}
#[inline]
pub fn try_iter(&mut self) -> TryIter<'_, T> {
TryIter(self)
}
#[inline]
pub(super) fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<T>> {
let chan = &self.chan;
if let Some(item) = chan.pop() {
chan.wake_senders();
return Poll::Ready(Some(item));
}
if chan.senders() == 0 || chan.is_closed() {
chan.clear_recv_waker();
return Poll::Ready(None);
}
chan.register_recv_waker(cx.waker());
if let Some(item) = chan.pop() {
chan.wake_senders();
return Poll::Ready(Some(item));
}
if chan.senders() == 0 || chan.is_closed() {
chan.clear_recv_waker();
return Poll::Ready(None);
}
Poll::Pending
}
#[inline(always)]
pub(super) fn chan(&self) -> &Chan<T> {
&self.chan
}
#[inline(always)]
pub fn len(&self) -> usize {
self.chan.len()
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.chan.is_empty()
}
#[inline(always)]
pub fn is_closed(&self) -> bool {
self.chan.senders() == 0 || self.chan.is_closed()
}
#[inline(always)]
pub fn close(&self) -> bool {
if self.is_closed() {
return false;
}
self.chan.close();
true
}
}
impl<T> Drop for Receiver<T> {
fn drop(&mut self) {
self.chan.clear_receiver();
struct DrainOnDrop<'a, T>(&'a Chan<T>);
impl<T> Drop for DrainOnDrop<'_, T> {
fn drop(&mut self) {
self.0.drain();
}
}
let drain = DrainOnDrop(&self.chan);
self.chan.wake_senders();
self.chan.clear_recv_waker();
drop(drain);
}
}
impl<T> Stream for Receiver<T> {
type Item = T;
#[inline]
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<T>> {
self.get_mut().poll_recv(cx)
}
}
impl<T> FusedStream for Receiver<T> {
#[inline]
fn is_terminated(&self) -> bool {
(self.chan.senders() == 0 || self.chan.is_closed()) && self.chan.is_empty()
}
}
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.try_recv().ok()
}
}