use std::sync::Arc;
use concurrent_queue::ConcurrentQueue;
use crate::synca::mpp::RecvIterator;
#[derive(Clone)]
pub enum StreamSpread<D, P> {
Pending(P),
Done(D),
}
impl<D: PartialEq, P: PartialEq> PartialEq for StreamSpread<D, P> {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Done(me), Self::Done(them)) => me == them,
(Self::Pending(me), Self::Pending(them)) => me == them,
_ => false,
}
}
}
impl<D: core::fmt::Debug, P: core::fmt::Debug> core::fmt::Display for StreamSpread<D, P> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Pending(p) => write!(f, "Pending({p:?})"),
Self::Done(d) => write!(f, "Next({d:?})"),
}
}
}
impl<D: core::fmt::Debug, P: core::fmt::Debug> core::fmt::Debug for StreamSpread<D, P> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Pending(p) => f.debug_tuple("Pending").field(p).finish(),
Self::Done(d) => f.debug_tuple("Next").field(d).finish(),
}
}
}
#[derive(PartialEq, Clone)]
pub enum Stream<D, P> {
Init,
Ignore,
Delayed(std::time::Duration),
Pending(P),
Next(D),
Wait,
Spread(Vec<StreamSpread<D, P>>),
}
impl<D: core::fmt::Debug, P: core::fmt::Debug> core::fmt::Display for Stream<D, P> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Stream::Init => write!(f, "Init"),
Stream::Ignore => write!(f, "Ignore"),
Stream::Delayed(d) => write!(f, "Delayed({d:?})"),
Stream::Pending(p) => write!(f, "Pending({p:?})"),
Stream::Next(d) => write!(f, "Next({d:?})"),
Stream::Wait => write!(f, "Wait"),
Stream::Spread(items) => write!(f, "Spread({items:?})"),
}
}
}
impl<D: core::fmt::Debug, P: core::fmt::Debug> core::fmt::Debug for Stream<D, P> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Stream::Init => f.write_str("Init"),
Stream::Ignore => f.write_str("Ignore"),
Stream::Delayed(d) => f.debug_tuple("Delayed").field(d).finish(),
Stream::Pending(p) => f.debug_tuple("Pending").field(p).finish(),
Stream::Next(d) => f.debug_tuple("Next").field(d).finish(),
Stream::Wait => f.write_str("Wait"),
Stream::Spread(items) => f.debug_tuple("Spread").field(items).finish(),
}
}
}
pub trait StreamIterator: Iterator<Item = Stream<Self::D, Self::P>> {
type D;
type P;
}
#[cfg(feature = "multi")]
impl<M, D, P> StreamIterator for M
where
M: Iterator<Item = Stream<D, P>> + ?Sized,
D: Send + 'static,
P: Send + 'static,
{
type D = D;
type P = P;
}
#[cfg(not(feature = "multi"))]
impl<M, D, P> StreamIterator for M
where
M: Iterator<Item = Stream<D, P>> + ?Sized,
D: 'static,
P: 'static,
{
type D = D;
type P = P;
}
#[deprecated(since = "1.3.0", note = "Use ConcurrentQueueStreamIterator instead")]
pub struct StreamRecvIterator<D, P>(RecvIterator<Stream<D, P>>);
#[allow(deprecated)]
impl<D, P> StreamRecvIterator<D, P> {
#[must_use]
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
#[must_use]
pub fn len(&self) -> usize {
self.0.len()
}
#[must_use]
pub fn is_closed(&self) -> bool {
self.0.is_closed()
}
}
#[allow(deprecated)]
impl<D, P> StreamRecvIterator<D, P> {
#[must_use]
pub fn new(iter: RecvIterator<Stream<D, P>>) -> Self {
Self(iter)
}
}
#[allow(deprecated)]
impl<D, P> Iterator for StreamRecvIterator<D, P> {
type Item = Stream<D, P>;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
use concurrent_queue::PopError;
use std::time::Duration;
pub struct ConcurrentQueueStreamIterator<D, P> {
chan: Arc<ConcurrentQueue<Stream<D, P>>>,
max_turns: usize,
park_duration: Duration,
}
impl<D, P> ConcurrentQueueStreamIterator<D, P> {
pub fn new(
chan: Arc<ConcurrentQueue<Stream<D, P>>>,
max_turns: usize,
park_duration: Duration,
) -> Self {
assert!(max_turns > 0, "max_turns must be greater than 0");
tracing::trace!(
max_turns = max_turns,
park_duration_ns = park_duration.as_nanos(),
"created ConcurrentQueueStreamIterator"
);
Self {
chan,
max_turns,
park_duration,
}
}
#[must_use]
pub fn chan(&self) -> &Arc<ConcurrentQueue<Stream<D, P>>> {
&self.chan
}
#[must_use]
pub fn max_turns(&self) -> usize {
self.max_turns
}
#[must_use]
pub fn park_duration(&self) -> Duration {
self.park_duration
}
#[must_use]
pub fn is_closed(&self) -> bool {
self.chan.is_closed()
}
#[must_use]
pub fn len(&self) -> usize {
self.chan.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.chan.is_empty()
}
}
impl<D, P> Iterator for ConcurrentQueueStreamIterator<D, P> {
type Item = Stream<D, P>;
fn next(&mut self) -> Option<Self::Item> {
tracing::trace!(max_turns = self.max_turns, "starting poll cycle");
for turn in 0..self.max_turns {
match self.chan.pop() {
Ok(value) => {
tracing::debug!(turn = turn, "received value from queue");
return Some(value);
}
Err(PopError::Empty) => {
#[cfg(feature = "std")]
std::thread::park_timeout(self.park_duration);
#[cfg(not(feature = "std"))]
std::hint::spin_loop();
}
Err(PopError::Closed) => {
tracing::debug!("queue closed, ending iteration");
return None;
}
}
}
tracing::trace!("max_turns reached, yielding Ignore");
Some(Stream::Ignore)
}
}
pub enum ShortCircuit<D, P> {
Continue(Stream<D, P>),
ReturnAndStop(Stream<D, P>),
Stop,
}