use crate::stream::AsyncStream;
#[cfg(feature = "trace_log")]
use crate::tokio_task_id;
use crate::{shared::*, trace_log, MRx, Rx};
use std::cell::Cell;
use std::fmt;
use std::future::Future;
use std::marker::PhantomData;
use std::ops::Deref;
use std::pin::Pin;
use std::sync::Arc;
use std::task::{Context, Poll};
pub struct AsyncRx<T> {
pub(crate) shared: Arc<ChannelShared<T>>,
_phan: PhantomData<Cell<()>>,
}
unsafe impl<T: Send> Send for AsyncRx<T> {}
impl<T> fmt::Debug for AsyncRx<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "AsyncRx")
}
}
impl<T> fmt::Display for AsyncRx<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "AsyncRx")
}
}
impl<T> Drop for AsyncRx<T> {
fn drop(&mut self) {
self.shared.close_rx();
}
}
impl<T> From<Rx<T>> for AsyncRx<T> {
fn from(value: Rx<T>) -> Self {
value.add_rx();
Self::new(value.shared.clone())
}
}
impl<T> AsyncRx<T> {
#[inline]
pub(crate) fn new(shared: Arc<ChannelShared<T>>) -> Self {
Self { shared, _phan: Default::default() }
}
#[inline(always)]
pub fn recv<'a>(&'a self) -> RecvFuture<'a, T> {
return RecvFuture { rx: self, waker: None };
}
#[cfg(any(feature = "tokio", feature = "async_std"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "tokio", feature = "async_std"))))]
#[inline]
pub fn recv_timeout<'a>(
&'a self, duration: std::time::Duration,
) -> RecvTimeoutFuture<'a, T, ()> {
let sleep = {
#[cfg(feature = "tokio")]
{
tokio::time::sleep(duration)
}
#[cfg(feature = "async_std")]
{
async_std::task::sleep(duration)
}
};
self.recv_with_timer(sleep)
}
#[inline]
pub fn recv_with_timer<'a, F, R>(&'a self, fut: F) -> RecvTimeoutFuture<'a, T, R>
where
F: Future<Output = R> + 'static,
{
return RecvTimeoutFuture { rx: self, waker: None, sleep: Box::pin(fut) };
}
#[inline(always)]
pub fn try_recv(&self) -> Result<T, TryRecvError> {
if let Some(item) = self.shared.inner.try_recv() {
self.shared.on_recv();
return Ok(item);
} else {
if self.shared.is_disconnected() {
if let Some(item) = self.shared.inner.try_recv() {
self.shared.on_recv();
return Ok(item);
}
return Err(TryRecvError::Disconnected);
}
return Err(TryRecvError::Empty);
}
}
#[inline(always)]
pub(crate) fn poll_item(
&self, ctx: &mut Context, o_waker: &mut Option<RecvWaker>, stream: bool,
) -> Result<T, TryRecvError> {
let shared = &self.shared;
macro_rules! try_recv {
($state: expr) => {
if let Some(item) = shared.inner.try_recv() {
shared.on_recv();
if let Some(waker) = o_waker.take() {
trace_log!("rx{:?}: recv {:?} {}", tokio_task_id!(), waker, $state);
if $state < WakerState::Woken as u8 {
shared.recvs.cancel_waker(&waker);
}
} else {
trace_log!("rx{:?}: recv", tokio_task_id!());
}
return Ok(item);
}
};
}
loop {
try_recv!(WakerState::Woken as u8);
if let Some(waker) = o_waker.as_ref() {
match waker.try_change_state(WakerState::Woken, WakerState::Init) {
Ok(_) => {
if !waker.will_wake(ctx) {
let _ = o_waker.take();
}
}
Err(state) => {
if state < WakerState::Woken as u8 {
if waker.will_wake(ctx) {
trace_log!("rx{:?}: will_wake {:?}", tokio_task_id!(), waker);
break;
} else {
shared.recvs.cancel_waker(&waker);
trace_log!("rx{:?}: drop waker {:?}", tokio_task_id!(), waker);
let _ = o_waker.take(); }
} else if state == WakerState::Closed as u8 {
break;
}
}
}
} else {
if let Some(mut backoff) = shared.get_async_backoff() {
loop {
backoff.spin();
if let Some(item) = shared.inner.try_recv() {
shared.on_recv();
trace_log!("rx{:?}: recv", tokio_task_id!());
return Ok(item);
}
if backoff.is_completed() {
break;
}
}
}
}
if let Some(waker) = o_waker.take() {
shared.reg_recv(&waker);
o_waker.replace(waker);
} else {
let waker = RecvWaker::new_async(ctx, ());
shared.reg_recv(&waker);
o_waker.replace(waker);
}
if !shared.is_empty() {
try_recv!(WakerState::Init as u8);
}
if !stream {
let _waker = o_waker.as_ref().unwrap();
let state = _waker.commit_waiting();
trace_log!("rx{:?}: commit_waiting {:?} {}", tokio_task_id!(), _waker, state);
if state == WakerState::Woken as u8 {
continue;
}
}
break;
}
if shared.is_disconnected() {
try_recv!(WakerState::Closed as u8);
trace_log!("rx{:?}: disconnected {:?}", tokio_task_id!(), o_waker);
return Err(TryRecvError::Disconnected);
} else {
return Err(TryRecvError::Empty);
}
}
#[inline]
pub fn into_stream(self) -> AsyncStream<T>
where
T: Send + Unpin + 'static,
{
AsyncStream::new(self)
}
#[inline]
pub fn into_blocking(self) -> Rx<T> {
self.into()
}
}
#[must_use]
pub struct RecvFuture<'a, T> {
rx: &'a AsyncRx<T>,
waker: Option<RecvWaker>,
}
unsafe impl<T: Send> Send for RecvFuture<'_, T> {}
impl<T> Drop for RecvFuture<'_, T> {
fn drop(&mut self) {
if let Some(waker) = self.waker.take() {
self.rx.shared.abandon_recv_waker(waker);
}
}
}
impl<T> Future for RecvFuture<'_, T> {
type Output = Result<T, RecvError>;
fn poll(self: Pin<&mut Self>, ctx: &mut Context) -> Poll<Self::Output> {
let mut _self = self.get_mut();
match _self.rx.poll_item(ctx, &mut _self.waker, false) {
Err(e) => {
if !e.is_empty() {
let _ = _self.waker.take();
return Poll::Ready(Err(RecvError {}));
} else {
return Poll::Pending;
}
}
Ok(item) => {
debug_assert!(_self.waker.is_none());
return Poll::Ready(Ok(item));
}
}
}
}
#[must_use]
pub struct RecvTimeoutFuture<'a, T, R> {
rx: &'a AsyncRx<T>,
waker: Option<RecvWaker>,
sleep: Pin<Box<dyn Future<Output = R>>>,
}
unsafe impl<T: Unpin + Send, R> Send for RecvTimeoutFuture<'_, T, R> {}
impl<T, R> Drop for RecvTimeoutFuture<'_, T, R> {
fn drop(&mut self) {
if let Some(waker) = self.waker.take() {
self.rx.shared.abandon_recv_waker(waker);
}
}
}
impl<T, R> Future for RecvTimeoutFuture<'_, T, R> {
type Output = Result<T, RecvTimeoutError>;
fn poll(self: Pin<&mut Self>, ctx: &mut Context) -> Poll<Self::Output> {
let mut _self = self.get_mut();
match _self.rx.poll_item(ctx, &mut _self.waker, false) {
Err(TryRecvError::Empty) => {
if let Poll::Ready(_) = _self.sleep.as_mut().poll(ctx) {
return Poll::Ready(Err(RecvTimeoutError::Timeout));
}
return Poll::Pending;
}
Err(TryRecvError::Disconnected) => {
return Poll::Ready(Err(RecvTimeoutError::Disconnected));
}
Ok(item) => {
return Poll::Ready(Ok(item));
}
}
}
}
pub trait AsyncRxTrait<T: Unpin + Send + 'static>:
Send + 'static + fmt::Debug + fmt::Display + AsRef<ChannelShared<T>> + Into<AsyncStream<T>>
{
fn recv<'a>(&'a self) -> RecvFuture<'a, T>;
#[cfg(any(feature = "tokio", feature = "async_std"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "tokio", feature = "async_std"))))]
fn recv_timeout<'a>(&'a self, timeout: std::time::Duration) -> RecvTimeoutFuture<'a, T, ()>;
fn recv_with_timer<'a, F, R>(&'a self, fut: F) -> RecvTimeoutFuture<'a, T, R>
where
F: Future<Output = R> + 'static;
fn try_recv(&self) -> Result<T, TryRecvError>;
#[inline(always)]
fn len(&self) -> usize {
self.as_ref().len()
}
#[inline(always)]
fn capacity(&self) -> Option<usize> {
self.as_ref().capacity()
}
#[inline(always)]
fn is_empty(&self) -> bool {
self.as_ref().is_empty()
}
#[inline(always)]
fn is_full(&self) -> bool {
self.as_ref().is_full()
}
#[inline(always)]
fn is_disconnected(&self) -> bool {
self.as_ref().is_disconnected()
}
fn clone_to_vec(self, count: usize) -> Vec<Self>
where
Self: Sized;
}
impl<T: Unpin + Send + 'static> AsyncRxTrait<T> for AsyncRx<T> {
#[inline(always)]
fn clone_to_vec(self, _count: usize) -> Vec<Self> {
assert_eq!(_count, 1);
vec![self]
}
#[inline(always)]
fn recv<'a>(&'a self) -> RecvFuture<'a, T> {
AsyncRx::recv(self)
}
#[cfg(any(feature = "tokio", feature = "async_std"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "tokio", feature = "async_std"))))]
#[inline(always)]
fn recv_timeout<'a>(&'a self, duration: std::time::Duration) -> RecvTimeoutFuture<'a, T, ()> {
AsyncRx::recv_timeout(self, duration)
}
#[inline(always)]
fn recv_with_timer<'a, F, R>(&'a self, fut: F) -> RecvTimeoutFuture<'a, T, R>
where
F: Future<Output = R> + 'static,
{
AsyncRx::recv_with_timer(self, fut)
}
#[inline(always)]
fn try_recv(&self) -> Result<T, TryRecvError> {
AsyncRx::<T>::try_recv(self)
}
}
pub struct MAsyncRx<T>(pub(crate) AsyncRx<T>);
impl<T> fmt::Debug for MAsyncRx<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "MAsyncRx")
}
}
impl<T> fmt::Display for MAsyncRx<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "MAsyncRx")
}
}
unsafe impl<T: Send> Sync for MAsyncRx<T> {}
impl<T> Clone for MAsyncRx<T> {
#[inline]
fn clone(&self) -> Self {
let inner = &self.0;
inner.shared.add_rx();
Self(AsyncRx::new(inner.shared.clone()))
}
}
impl<T> From<MAsyncRx<T>> for AsyncRx<T> {
fn from(rx: MAsyncRx<T>) -> Self {
rx.0
}
}
impl<T> MAsyncRx<T> {
#[inline]
pub(crate) fn new(shared: Arc<ChannelShared<T>>) -> Self {
Self(AsyncRx::new(shared))
}
#[inline]
pub fn into_stream(self) -> AsyncStream<T>
where
T: Send + Unpin + 'static,
{
AsyncStream::new(self.0)
}
#[inline]
pub fn into_blocking(self) -> MRx<T> {
self.into()
}
}
impl<T> Deref for MAsyncRx<T> {
type Target = AsyncRx<T>;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> From<MRx<T>> for MAsyncRx<T> {
fn from(value: MRx<T>) -> Self {
value.add_rx();
Self::new(value.shared.clone())
}
}
impl<T: Unpin + Send + 'static> AsyncRxTrait<T> for MAsyncRx<T> {
#[inline(always)]
fn clone_to_vec(self, count: usize) -> Vec<Self> {
let mut v = Vec::with_capacity(count);
for _ in 0..count - 1 {
v.push(self.clone());
}
v.push(self);
v
}
#[inline(always)]
fn try_recv(&self) -> Result<T, TryRecvError> {
self.0.try_recv()
}
#[inline(always)]
fn recv<'a>(&'a self) -> RecvFuture<'a, T> {
self.0.recv()
}
#[cfg(any(feature = "tokio", feature = "async_std"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "tokio", feature = "async_std"))))]
#[inline(always)]
fn recv_timeout<'a>(&'a self, duration: std::time::Duration) -> RecvTimeoutFuture<'a, T, ()> {
self.0.recv_timeout(duration)
}
#[inline(always)]
fn recv_with_timer<'a, F, R>(&'a self, fut: F) -> RecvTimeoutFuture<'a, T, R>
where
F: Future<Output = R> + 'static,
{
self.0.recv_with_timer(fut)
}
}
impl<T> Deref for AsyncRx<T> {
type Target = ChannelShared<T>;
#[inline(always)]
fn deref(&self) -> &ChannelShared<T> {
&self.shared
}
}
impl<T> AsRef<ChannelShared<T>> for AsyncRx<T> {
#[inline(always)]
fn as_ref(&self) -> &ChannelShared<T> {
&self.shared
}
}
impl<T> AsRef<ChannelShared<T>> for MAsyncRx<T> {
#[inline(always)]
fn as_ref(&self) -> &ChannelShared<T> {
&self.0.shared
}
}