use crate::backoff::*;
use crate::{shared::*, trace_log, AsyncRx, MAsyncRx};
use std::cell::Cell;
use std::fmt;
use std::marker::PhantomData;
use std::ops::Deref;
use std::sync::Arc;
use std::time::{Duration, Instant};
pub struct Rx<T> {
pub(crate) shared: Arc<ChannelShared<T>>,
_phan: PhantomData<Cell<()>>,
waker_cache: WakerCache<()>,
}
unsafe impl<T: Send> Send for Rx<T> {}
impl<T> fmt::Debug for Rx<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Rx")
}
}
impl<T> fmt::Display for Rx<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Rx")
}
}
impl<T> Drop for Rx<T> {
fn drop(&mut self) {
self.shared.close_rx();
}
}
impl<T> From<AsyncRx<T>> for Rx<T> {
fn from(value: AsyncRx<T>) -> Self {
value.add_rx();
Self::new(value.shared.clone())
}
}
impl<T> Rx<T> {
#[inline(always)]
pub(crate) fn new(shared: Arc<ChannelShared<T>>) -> Self {
Self { shared, waker_cache: WakerCache::new(), _phan: Default::default() }
}
#[inline(always)]
pub(crate) fn _recv_blocking(&self, deadline: Option<Instant>) -> Result<T, RecvTimeoutError> {
let shared = &self.shared;
macro_rules! try_recv {
() => {
if let Some(item) = shared.inner.try_recv() {
shared.on_recv();
trace_log!("rx: recv");
return Ok(item);
}
};
($waker: expr) => {
if let Some(item) = shared.inner.try_recv() {
shared.on_recv();
trace_log!("rx: recv {:?}", $waker);
self.waker_cache.push($waker);
return Ok(item);
}
};
}
try_recv!();
let mut cfg = BackoffConfig::default().limit(shared.backoff_limit);
if shared.large {
cfg = cfg.spin(2);
}
let mut backoff = Backoff::new(cfg);
loop {
let r = backoff.snooze();
try_recv!();
if r {
break;
}
}
let waker = self.waker_cache.new_blocking(());
let mut state;
'MAIN: loop {
if waker.get_state() == WakerState::Woken as u8 {
waker.reset_init();
}
shared.reg_recv(&waker);
if shared.is_empty() {
state = waker.commit_waiting();
} else {
if let Some(item) = shared.inner.try_recv() {
shared.on_recv();
trace_log!("rx: recv cancel {:?} Init", waker);
self.recvs.cancel_waker(&waker);
return Ok(item);
}
state = waker.commit_waiting();
}
trace_log!("rx: {:?} commit_waiting state={}", waker, state);
if shared.is_disconnected() {
break 'MAIN;
}
while state == WakerState::Waiting as u8 {
match check_timeout(deadline) {
Ok(None) => {
std::thread::park();
}
Ok(Some(dur)) => {
std::thread::park_timeout(dur);
}
Err(_) => {
let _ = shared.abandon_recv_waker(waker);
return Err(RecvTimeoutError::Timeout);
}
}
state = waker.get_state();
}
if state == WakerState::Closed as u8 {
break 'MAIN;
}
backoff.reset();
loop {
try_recv!(waker);
if backoff.snooze() {
break;
}
}
}
try_recv!(waker);
return Err(RecvTimeoutError::Disconnected);
}
#[inline]
pub fn recv<'a>(&'a self) -> Result<T, RecvError> {
self._recv_blocking(None).map_err(|err| match err {
RecvTimeoutError::Disconnected => RecvError,
RecvTimeoutError::Timeout => unreachable!(),
})
}
#[inline]
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]
pub fn recv_timeout(&self, timeout: Duration) -> Result<T, RecvTimeoutError> {
match Instant::now().checked_add(timeout) {
Some(deadline) => self._recv_blocking(Some(deadline)),
None => self.try_recv().map_err(|e| match e {
TryRecvError::Disconnected => RecvTimeoutError::Disconnected,
TryRecvError::Empty => RecvTimeoutError::Timeout,
}),
}
}
}
pub struct MRx<T>(pub(crate) Rx<T>);
impl<T> fmt::Debug for MRx<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "MRx")
}
}
impl<T> fmt::Display for MRx<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "MRx")
}
}
unsafe impl<T: Send> Sync for MRx<T> {}
impl<T> MRx<T> {
#[inline(always)]
pub(crate) fn new(shared: Arc<ChannelShared<T>>) -> Self {
Self(Rx::new(shared))
}
}
impl<T> Clone for MRx<T> {
#[inline(always)]
fn clone(&self) -> Self {
let inner = &self.0;
inner.shared.add_rx();
Self(Rx::new(inner.shared.clone()))
}
}
impl<T> Deref for MRx<T> {
type Target = Rx<T>;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> From<MRx<T>> for Rx<T> {
fn from(rx: MRx<T>) -> Self {
rx.0
}
}
impl<T> From<MAsyncRx<T>> for MRx<T> {
fn from(value: MAsyncRx<T>) -> Self {
value.add_rx();
Self::new(value.shared.clone())
}
}
pub trait BlockingRxTrait<T: Send + 'static>:
Send + 'static + fmt::Debug + fmt::Display + AsRef<ChannelShared<T>>
{
fn recv<'a>(&'a self) -> Result<T, RecvError>;
fn try_recv(&self) -> Result<T, TryRecvError>;
fn recv_timeout(&self, timeout: Duration) -> Result<T, RecvTimeoutError>;
#[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: Send + 'static> BlockingRxTrait<T> for Rx<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) -> Result<T, RecvError> {
Rx::recv(self)
}
#[inline(always)]
fn try_recv(&self) -> Result<T, TryRecvError> {
Rx::try_recv(self)
}
#[inline(always)]
fn recv_timeout(&self, timeout: Duration) -> Result<T, RecvTimeoutError> {
Rx::recv_timeout(self, timeout)
}
}
impl<T: Send + 'static> BlockingRxTrait<T> for MRx<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 recv<'a>(&'a self) -> Result<T, RecvError> {
self.0.recv()
}
#[inline(always)]
fn try_recv(&self) -> Result<T, TryRecvError> {
self.0.try_recv()
}
#[inline(always)]
fn recv_timeout(&self, timeout: Duration) -> Result<T, RecvTimeoutError> {
self.0.recv_timeout(timeout)
}
}
impl<T> Deref for Rx<T> {
type Target = ChannelShared<T>;
#[inline(always)]
fn deref(&self) -> &ChannelShared<T> {
&self.shared
}
}
impl<T> AsRef<ChannelShared<T>> for Rx<T> {
#[inline(always)]
fn as_ref(&self) -> &ChannelShared<T> {
&self.shared
}
}
impl<T> AsRef<ChannelShared<T>> for MRx<T> {
#[inline(always)]
fn as_ref(&self) -> &ChannelShared<T> {
&self.0.shared
}
}