#![allow(clippy::type_complexity)]
use crate::valtron::{Ctx, Stream};
use concurrent_queue::ConcurrentQueue;
use derive_more::From;
use std::{
any::Any,
cell::{self, RefCell},
marker::PhantomData,
rc::{self, Rc},
sync::Arc,
time,
};
use crate::compati::Mutex;
use foundation_compact::rng::ChaCha8Rng;
use std::sync::atomic::{AtomicBool, Ordering};
use crate::{
synca::Entry,
valtron::{AnyResult, GenericResult},
};
pub trait EventReadiness {
fn is_ready(&self, dur: Option<time::Duration>) -> bool;
}
#[cfg(feature = "multi")]
pub type EventReadinessPtr = Arc<dyn EventReadiness + Send + Sync>;
#[cfg(not(feature = "multi"))]
pub type EventReadinessPtr = Arc<dyn EventReadiness>;
#[derive(Clone)]
pub struct BoolSignal(Arc<AtomicBool>);
impl BoolSignal {
pub fn new(value: bool) -> Self {
Self(Arc::new(AtomicBool::new(value)))
}
pub fn from_atomic(inner: Arc<AtomicBool>) -> Self {
Self(inner)
}
pub fn clone_inner(&self) -> Arc<AtomicBool> {
self.0.clone()
}
}
impl EventReadiness for BoolSignal {
fn is_ready(&self, _dur: Option<time::Duration>) -> bool {
self.0.load(Ordering::SeqCst)
}
}
pub struct QueueReadiness<T>(Arc<ConcurrentQueue<T>>);
impl<T> Clone for QueueReadiness<T> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<T> QueueReadiness<T> {
pub fn new(queue: Arc<ConcurrentQueue<T>>) -> Self {
Self(queue)
}
pub fn queue(&self) -> Arc<ConcurrentQueue<T>> {
self.0.clone()
}
}
#[cfg(feature = "multi")]
impl<T: Send> EventReadiness for QueueReadiness<T> {
fn is_ready(&self, _dur: Option<time::Duration>) -> bool {
!self.0.is_empty() || self.0.is_closed()
}
}
#[cfg(not(feature = "multi"))]
impl<T> EventReadiness for QueueReadiness<T> {
fn is_ready(&self, _dur: Option<time::Duration>) -> bool {
!self.0.is_empty() || self.0.is_closed()
}
}
pub struct QueueVacancyReadiness<T>(Arc<ConcurrentQueue<T>>);
impl<T> Clone for QueueVacancyReadiness<T> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<T> QueueVacancyReadiness<T> {
pub fn new(queue: Arc<ConcurrentQueue<T>>) -> Self {
Self(queue)
}
pub fn queue(&self) -> Arc<ConcurrentQueue<T>> {
self.0.clone()
}
}
#[cfg(feature = "multi")]
impl<T: Send> EventReadiness for QueueVacancyReadiness<T> {
fn is_ready(&self, _dur: Option<time::Duration>) -> bool {
self.0.is_closed() || !self.0.is_full()
}
}
#[cfg(not(feature = "multi"))]
impl<T> EventReadiness for QueueVacancyReadiness<T> {
fn is_ready(&self, _dur: Option<time::Duration>) -> bool {
self.0.is_closed() || !self.0.is_full()
}
}
pub struct AnyReadiness(Vec<EventReadinessPtr>);
impl AnyReadiness {
pub fn new(children: Vec<EventReadinessPtr>) -> Self {
Self(children)
}
pub fn either(a: EventReadinessPtr, b: EventReadinessPtr) -> Self {
Self(vec![a, b])
}
#[must_use]
pub fn with(mut self, child: EventReadinessPtr) -> Self {
self.0.push(child);
self
}
}
impl EventReadiness for AnyReadiness {
fn is_ready(&self, dur: Option<time::Duration>) -> bool {
self.0.iter().any(|child| child.is_ready(dur))
}
}
pub type PanicHandler = dyn Fn(Box<dyn Any + Send>) + Send + Sync;
pub type BoxedPanicHandler = Box<PanicHandler>;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum SpawnType {
Sequenced,
Lifted,
LiftedWithParent,
Broadcasted,
Scheduled,
None,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct SpawnInfo(SpawnType, Option<Entry>, Option<Entry>);
impl SpawnInfo {
#[must_use]
pub fn new(st: SpawnType, task: Option<Entry>, parent: Option<Entry>) -> Self {
Self(st, task, parent)
}
#[must_use]
pub fn spawn_type(&self) -> SpawnType {
self.0
}
#[must_use]
pub fn child(&self) -> Option<Entry> {
self.1
}
#[must_use]
pub fn parent(&self) -> Option<Entry> {
self.2
}
#[must_use]
pub fn has_parent_and_child(&self) -> bool {
self.1.is_some() && self.2.is_some()
}
}
#[derive(Clone)]
pub enum TaskSpread<D, P> {
Pending(P),
Ready(D),
}
impl<D: core::fmt::Debug, P: core::fmt::Debug> core::fmt::Display for TaskSpread<D, P> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Pending(p) => write!(f, "Pending({p:?})"),
Self::Ready(d) => write!(f, "Next({d:?})"),
}
}
}
impl<D: core::fmt::Debug, P: core::fmt::Debug> core::fmt::Debug for TaskSpread<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::Ready(d) => f.debug_tuple("Ready").field(d).finish(),
}
}
}
impl<D: PartialEq, P: PartialEq> PartialEq for TaskSpread<D, P> {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Ready(me), Self::Ready(them)) => me == them,
(Self::Pending(me), Self::Pending(them)) => me == them,
_ => false,
}
}
}
pub enum TaskStatus<D, P> {
Delayed(time::Duration),
#[cfg(feature = "multi")]
Spawn(BoxedSendExecutionAction),
#[cfg(not(feature = "multi"))]
Spawn(BoxedExecutionAction),
Pending(P),
Init,
Ready(D),
Ignore,
Wait,
Spread(Vec<TaskSpread<D, P>>),
Depends(EventReadinessPtr),
}
impl<D, P> From<TaskStatus<D, P>> for Stream<D, P> {
fn from(val: TaskStatus<D, P>) -> Self {
match val {
TaskStatus::Init => Stream::Init,
TaskStatus::Spawn(_) => Stream::Ignore,
TaskStatus::Ready(inner) => Stream::Next(inner),
TaskStatus::Delayed(inner) => Stream::Delayed(inner),
TaskStatus::Pending(inner) => Stream::Pending(inner),
TaskStatus::Ignore => Stream::Ignore,
TaskStatus::Wait => Stream::Wait,
TaskStatus::Spread(items) => Stream::Spread(
items
.into_iter()
.map(|item| match item {
TaskSpread::Ready(d) => crate::valtron::streams::StreamSpread::Done(d),
TaskSpread::Pending(p) => crate::valtron::streams::StreamSpread::Pending(p),
})
.collect(),
),
TaskStatus::Depends(_) => Stream::Ignore,
}
}
}
impl<D: PartialEq, P: PartialEq> Eq for TaskStatus<D, P> {}
impl<D: PartialEq, P: PartialEq> PartialEq for TaskStatus<D, P> {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(TaskStatus::Delayed(me), TaskStatus::Delayed(them)) => me == them,
(TaskStatus::Pending(me), TaskStatus::Pending(them)) => me == them,
(TaskStatus::Ready(me), TaskStatus::Ready(them)) => me == them,
(TaskStatus::Spawn(_), TaskStatus::Spawn(_))
| (TaskStatus::Init, TaskStatus::Init)
| (TaskStatus::Ignore, TaskStatus::Ignore)
| (TaskStatus::Wait, TaskStatus::Wait)
| (TaskStatus::Depends(_), TaskStatus::Depends(_)) => true,
(TaskStatus::Spread(me), TaskStatus::Spread(them)) => me == them,
_ => false,
}
}
}
impl<D: core::fmt::Debug, P: core::fmt::Debug> core::fmt::Display for TaskStatus<D, P> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
#[allow(unused)]
#[derive(Debug)]
enum TStatus<'a, D, P> {
Delayed(time::Duration),
Pending(&'a P),
Ready(&'a D),
Init,
Spawn,
Ignore,
Wait,
Spread(&'a [TaskSpread<D, P>]),
Depends,
}
let debug_item = match self {
TaskStatus::Delayed(duration) => TStatus::Delayed(*duration),
TaskStatus::Pending(inner) => TStatus::Pending(inner),
TaskStatus::Ready(inner) => TStatus::Ready(inner),
TaskStatus::Spawn(_) => TStatus::Spawn,
TaskStatus::Init => TStatus::Init,
TaskStatus::Ignore => TStatus::Ignore,
TaskStatus::Wait => TStatus::Wait,
TaskStatus::Spread(items) => TStatus::Spread(items.as_slice()),
TaskStatus::Depends(_) => TStatus::Depends,
};
write!(f, "{debug_item:?}")
}
}
impl<D: core::fmt::Debug, P: core::fmt::Debug> core::fmt::Debug for TaskStatus<D, P> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
#[allow(unused)]
#[derive(Debug)]
enum TStatus<'a, D, P> {
Delayed(time::Duration),
Pending(&'a P),
Ready(&'a D),
Init,
Spawn,
Ignore,
Wait,
Spread(&'a [TaskSpread<D, P>]),
Depends,
}
let debug_item = match self {
TaskStatus::Delayed(duration) => TStatus::Delayed(*duration),
TaskStatus::Pending(inner) => TStatus::Pending(inner),
TaskStatus::Ready(inner) => TStatus::Ready(inner),
TaskStatus::Spawn(_) => TStatus::Spawn,
TaskStatus::Init => TStatus::Init,
TaskStatus::Ignore => TStatus::Ignore,
TaskStatus::Wait => TStatus::Wait,
TaskStatus::Spread(items) => TStatus::Spread(items.as_slice()),
TaskStatus::Depends(_) => TStatus::Depends,
};
write!(f, "{debug_item:?}")
}
}
pub type AsTaskIterator<D, P> = dyn Iterator<Item = TaskStatus<D, P>>;
pub type BoxedTaskIterator<D, P> = Box<dyn Iterator<Item = TaskStatus<D, P>>>;
pub trait TaskIterator {
type Pending;
type Ready;
fn next_status(&mut self, ctx: Ctx) -> Option<TaskStatus<Self::Ready, Self::Pending>>;
fn with_ctx(self, ctx: Ctx) -> TaskAsIterator<Self::Ready, Self::Pending>
where
Self: Sized + 'static,
Self::Ready: 'static,
Self::Pending: 'static,
{
TaskAsIterator::from_impl(self, ctx)
}
}
pub struct TaskIter<T: TaskIterator>(pub T);
impl<T: TaskIterator> TaskIterator for TaskIter<T> {
type Ready = T::Ready;
type Pending = T::Pending;
fn next_status(&mut self, ctx: Ctx) -> Option<TaskStatus<Self::Ready, Self::Pending>> {
self.0.next_status(ctx)
}
}
impl<D: 'static, P: 'static> TaskIterator for Box<dyn TaskIterator<Ready = D, Pending = P>> {
type Ready = D;
type Pending = P;
fn next_status(&mut self, ctx: Ctx) -> Option<TaskStatus<Self::Ready, Self::Pending>> {
(**self).next_status(ctx)
}
}
impl<D: 'static, P: 'static> TaskIterator for Box<dyn TaskIterator<Ready = D, Pending = P> + Send> {
type Ready = D;
type Pending = P;
fn next_status(&mut self, ctx: Ctx) -> Option<TaskStatus<Self::Ready, Self::Pending>> {
(**self).next_status(ctx)
}
}
pub struct TaskAsIterator<D, P>(Box<dyn TaskIterator<Ready = D, Pending = P>>, Ctx);
impl<D, P> TaskAsIterator<D, P> {
pub fn from_impl(t: impl TaskIterator<Ready = D, Pending = P> + 'static, ctx: Ctx) -> Self {
Self(Box::new(t), ctx)
}
#[must_use]
pub fn new(t: Box<dyn TaskIterator<Ready = D, Pending = P>>, ctx: Ctx) -> Self {
Self(t, ctx)
}
}
impl<D: 'static, P: 'static> Iterator for TaskAsIterator<D, P> {
type Item = TaskStatus<D, P>;
fn next(&mut self) -> Option<Self::Item> {
self.0.next_status(self.1.clone())
}
}
impl<D: 'static, P: 'static> TaskAsIterator<D, P> {
pub fn first_ready(mut self) -> Option<D> {
while let Some(status) = self.0.next_status(self.1.clone()) {
if let TaskStatus::Ready(value) = status {
return Some(value);
}
}
None
}
pub fn first_pending(mut self) -> Option<P> {
while let Some(status) = self.0.next_status(self.1.clone()) {
if let TaskStatus::Pending(value) = status {
return Some(value);
}
}
None
}
pub fn collect_ready(mut self) -> Vec<D> {
let mut out = Vec::new();
while let Some(status) = self.0.next_status(self.1.clone()) {
if let TaskStatus::Ready(value) = status {
out.push(value);
}
}
out
}
pub fn collect_one_ready(mut self) -> Option<D> {
while let Some(status) = self.0.next_status(self.1.clone()) {
if let TaskStatus::Ready(value) = status {
return Some(value);
}
}
None
}
}
#[derive(Clone)]
pub enum State {
Pending(Option<time::Duration>),
Panicked,
SpawnFailed(Entry),
SpawnFinished(SpawnInfo),
Reschedule,
Progressed,
ReadyValue(Entry),
Done,
Wait,
Depends(EventReadinessPtr),
}
impl core::fmt::Debug for State {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Pending(d) => f.debug_tuple("Pending").field(d).finish(),
Self::Panicked => write!(f, "Panicked"),
Self::SpawnFailed(e) => f.debug_tuple("SpawnFailed").field(e).finish(),
Self::SpawnFinished(s) => f.debug_tuple("SpawnFinished").field(s).finish(),
Self::Reschedule => write!(f, "Reschedule"),
Self::Progressed => write!(f, "Progressed"),
Self::ReadyValue(e) => f.debug_tuple("ReadyValue").field(e).finish(),
Self::Done => write!(f, "Done"),
Self::Wait => write!(f, "Wait"),
Self::Depends(_) => write!(f, "Depends"),
}
}
}
impl PartialEq for State {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Pending(a), Self::Pending(b)) => a == b,
(Self::Panicked, Self::Panicked) => true,
(Self::SpawnFailed(a), Self::SpawnFailed(b)) => a == b,
(Self::SpawnFinished(_), Self::SpawnFinished(_)) => true,
(Self::Reschedule, Self::Reschedule) => true,
(Self::Progressed, Self::Progressed) => true,
(Self::ReadyValue(a), Self::ReadyValue(b)) => a == b,
(Self::Done, Self::Done) => true,
(Self::Wait, Self::Wait) => true,
(Self::Depends(_), Self::Depends(_)) => true,
_ => false,
}
}
}
impl Eq for State {}
pub type BoxedStateIterator = Box<dyn Iterator<Item = State>>;
pub type BoxedSendStateIterator = Box<dyn Iterator<Item = State> + Send>;
pub type BoxedSendSyncStateIterator = Box<dyn Iterator<Item = State> + Send + Sync + 'static>;
#[cfg(feature = "multi")]
pub type SharedTaskQueue = Arc<ConcurrentQueue<BoxedSendExecutionIterator>>;
#[cfg(not(feature = "multi"))]
pub type SharedTaskQueue = Arc<ConcurrentQueue<BoxedExecutionIterator>>;
#[cfg(feature = "multi")]
pub type GlobalTask = BoxedSendExecutionIterator;
#[cfg(not(feature = "multi"))]
pub type GlobalTask = BoxedExecutionIterator;
pub type BoxedExecutionEngine = Box<dyn ExecutionEngine>;
pub trait ExecutionIterator {
fn next(&mut self, parent_id: Entry, engine: BoxedExecutionEngine, ctx: Ctx) -> Option<State>;
}
pub trait IntoBoxedExecutionIterator {
fn into_box_execution_iterator(self) -> Box<dyn ExecutionIterator>;
}
pub trait IntoBoxedSendExecutionIterator {
fn into_box_send_execution_iterator(self) -> Box<dyn ExecutionIterator + Send + 'static>;
}
impl<F> IntoBoxedSendExecutionIterator for F
where
F: ExecutionIterator + Send + 'static,
{
fn into_box_send_execution_iterator(self) -> Box<dyn ExecutionIterator + Send + 'static> {
Box::new(self)
}
}
impl<F> IntoBoxedExecutionIterator for F
where
F: ExecutionIterator + 'static,
{
fn into_box_execution_iterator(self) -> Box<dyn ExecutionIterator> {
Box::new(self)
}
}
pub type BoxedExecutionIterator = Box<dyn ExecutionIterator + 'static>;
pub type BoxedSendExecutionIterator = Box<dyn ExecutionIterator + Send + 'static>;
pub trait CloneableExecutionIterator: ExecutionIterator {
fn clone_execution_iterator(&self) -> Box<dyn CloneableExecutionIterator>;
}
pub trait IntoRawExecutionIterator: CloneableExecutionIterator {
fn into_execution_iterator(self) -> Box<dyn ExecutionIterator + Send + 'static>;
}
impl<M> IntoRawExecutionIterator for M
where
M: CloneableExecutionIterator + Send + 'static,
{
fn into_execution_iterator(self) -> Box<dyn ExecutionIterator + Send + 'static> {
Box::new(self)
}
}
impl<M> CloneableExecutionIterator for M
where
M: ExecutionIterator + Clone + 'static,
{
fn clone_execution_iterator(&self) -> Box<dyn CloneableExecutionIterator> {
Box::new(self.clone())
}
}
pub struct CanCloneExecutionIterator(Box<dyn CloneableExecutionIterator>);
impl CanCloneExecutionIterator {
#[must_use]
pub fn new(elem: Box<dyn CloneableExecutionIterator>) -> Self {
Self(elem)
}
}
impl Clone for CanCloneExecutionIterator {
fn clone(&self) -> Self {
Self(self.0.clone_execution_iterator())
}
}
impl ExecutionIterator for CanCloneExecutionIterator {
fn next(&mut self, entry: Entry, engine: BoxedExecutionEngine, ctx: Ctx) -> Option<State> {
self.0.next(entry, engine, ctx)
}
}
#[allow(clippy::needless_lifetimes)]
impl<'a, M> ExecutionIterator for &'a mut M
where
M: ExecutionIterator,
{
fn next(&mut self, entry: Entry, engine: BoxedExecutionEngine, ctx: Ctx) -> Option<State> {
(**self).next(entry, engine, ctx)
}
}
impl<M> ExecutionIterator for RefCell<Box<M>>
where
M: ExecutionIterator + ?Sized,
{
fn next(&mut self, entry: Entry, engine: BoxedExecutionEngine, ctx: Ctx) -> Option<State> {
self.get_mut().next(entry, engine, ctx)
}
}
impl<M> ExecutionIterator for Rc<RefCell<Box<M>>>
where
M: ExecutionIterator + ?Sized,
{
fn next(&mut self, entry: Entry, engine: BoxedExecutionEngine, ctx: Ctx) -> Option<State> {
self.borrow_mut().next(entry, engine, ctx)
}
}
impl<M> ExecutionIterator for Mutex<Box<M>>
where
M: ExecutionIterator + ?Sized,
{
fn next(&mut self, entry: Entry, engine: BoxedExecutionEngine, ctx: Ctx) -> Option<State> {
self.get_mut().unwrap().next(entry, engine, ctx)
}
}
impl<M> ExecutionIterator for Arc<Mutex<Box<M>>>
where
M: ExecutionIterator + ?Sized,
{
fn next(&mut self, entry: Entry, engine: BoxedExecutionEngine, ctx: Ctx) -> Option<State> {
self.lock().unwrap().next(entry, engine, ctx)
}
}
impl<M> ExecutionIterator for Box<M>
where
M: ExecutionIterator + ?Sized,
{
fn next(&mut self, entry: Entry, engine: BoxedExecutionEngine, ctx: Ctx) -> Option<State> {
(**self).next(entry, engine, ctx)
}
}
#[derive(Debug, From)]
pub enum ExecutorError {
FailedToLift,
FailedToSchedule,
AlreadyLiftedTask,
ParentMustBeExecutingToLift,
QueueClosed,
QueueFull,
FailedToCreate,
NotSupported,
TaskRequired,
#[from(ignore)]
FailedToSendThreadActivity,
ParentMustBeSupplied,
}
impl std::error::Error for ExecutorError {}
impl core::fmt::Display for ExecutorError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{self:?}")
}
}
pub trait ExecutionEngine {
fn sequenced(
&self,
task: BoxedExecutionIterator,
parent: Entry,
) -> AnyResult<SpawnInfo, ExecutorError>;
fn lift(
&self,
task: BoxedExecutionIterator,
parent: Option<Entry>,
) -> AnyResult<SpawnInfo, ExecutorError>;
fn schedule(&self, task: BoxedExecutionIterator) -> AnyResult<SpawnInfo, ExecutorError>;
fn broadcast(&self, task: GlobalTask) -> AnyResult<SpawnInfo, ExecutorError>;
fn broadcast_or_lift(
&self,
task: GlobalTask,
parent: Option<Entry>,
) -> AnyResult<SpawnInfo, ExecutorError> {
#[cfg(feature = "multi")]
{
let _ = parent;
self.broadcast(task)
}
#[cfg(not(feature = "multi"))]
{
self.lift(task, parent)
}
}
fn broadcast_or_sequence(
&self,
task: GlobalTask,
parent: Entry,
) -> AnyResult<SpawnInfo, ExecutorError> {
#[cfg(feature = "multi")]
{
let _ = parent;
self.broadcast(task)
}
#[cfg(not(feature = "multi"))]
{
self.sequenced(task, parent)
}
}
fn boxed_engine(&self) -> BoxedExecutionEngine;
fn shared_queue(&self) -> SharedTaskQueue;
fn rng(&self) -> rc::Rc<cell::RefCell<ChaCha8Rng>>;
}
pub type BoxedExecutionAction = Box<dyn ExecutionAction>;
pub type BoxedSendExecutionAction = Box<dyn ExecutionAction + Send + 'static>;
pub trait ExecutionAction {
fn apply(
&mut self,
key: Option<Entry>,
engine: BoxedExecutionEngine,
) -> GenericResult<SpawnInfo>;
}
impl<M> ExecutionAction for Box<M>
where
M: ExecutionAction + ?Sized,
{
fn apply(
&mut self,
key: Option<Entry>,
engine: BoxedExecutionEngine,
) -> GenericResult<SpawnInfo> {
(**self).apply(key, engine)
}
}
pub trait IntoBoxedSendExecutionAction {
fn into_box_send_execution_action(self) -> Box<dyn ExecutionAction + Send + 'static>;
}
impl<F> IntoBoxedSendExecutionAction for F
where
F: ExecutionAction + Send + 'static,
{
fn into_box_send_execution_action(self) -> Box<dyn ExecutionAction + Send + 'static> {
Box::new(self)
}
}
pub trait IntoBoxedExecutionAction {
fn into_box_execution_action(self) -> Box<dyn ExecutionAction>;
}
impl<F> IntoBoxedExecutionAction for F
where
F: ExecutionAction + 'static,
{
fn into_box_execution_action(self) -> Box<dyn ExecutionAction> {
Box::new(self)
}
}
#[derive(Default, Clone, Debug)]
pub struct NoAction;
impl ExecutionAction for NoAction {
fn apply(
&mut self,
_entry: Option<Entry>,
_engine: BoxedExecutionEngine,
) -> GenericResult<SpawnInfo> {
Ok(SpawnInfo::new(SpawnType::None, None, None))
}
}
pub type BoxedTaskReadyResolver<D, P> = Box<dyn TaskReadyResolver<D, P>>;
pub type BoxedSendTaskReadyResolver<D, P> = Box<dyn TaskReadyResolver<D, P> + Send + 'static>;
pub trait TaskReadyResolver<D, P> {
fn handle(&self, item: TaskStatus<D, P>, engine: BoxedExecutionEngine);
}
pub trait IntoBoxedSendTaskReadyResolver<D, P> {
fn into_box_send_task_ready_resolver(self) -> Box<dyn TaskReadyResolver<D, P> + Send + 'static>;
}
impl<F, D, P> IntoBoxedSendTaskReadyResolver<D, P> for F
where
F: TaskReadyResolver<D, P> + Send + 'static,
{
fn into_box_send_task_ready_resolver(self) -> Box<dyn TaskReadyResolver<D, P> + Send + 'static> {
Box::new(self)
}
}
pub trait IntoBoxedTaskReadyResolver<D, P> {
fn into_box_task_ready_resolver(self) -> Box<dyn TaskReadyResolver<D, P>>;
}
impl<F, D, P> IntoBoxedTaskReadyResolver<D, P> for F
where
F: TaskReadyResolver<D, P> + Send + 'static,
{
fn into_box_task_ready_resolver(self) -> Box<dyn TaskReadyResolver<D, P>> {
Box::new(self)
}
}
pub type NoResolver<Done, Pending> = NoResolving<Done, Pending>;
pub struct NoResolving<Done, Pending>(PhantomData<(Done, Pending)>);
impl<Done, Pending> NoResolving<Done, Pending> {
#[must_use]
pub fn new() -> Self {
Self(PhantomData)
}
}
impl<Done, Pending> Default for NoResolving<Done, Pending> {
fn default() -> Self {
Self::new()
}
}
impl<Done, Pending> TaskReadyResolver<Done, Pending> for NoResolving<Done, Pending> {
fn handle(&self, _item: TaskStatus<Done, Pending>, _engine: BoxedExecutionEngine) {
}
}
#[allow(clippy::needless_lifetimes)]
impl<'a, F, D, P> TaskReadyResolver<D, P> for &'a mut F
where
F: TaskReadyResolver<D, P>,
{
fn handle(&self, item: TaskStatus<D, P>, engine: BoxedExecutionEngine) {
(**self).handle(item, engine);
}
}
impl<F, D, P> TaskReadyResolver<D, P> for Box<F>
where
F: TaskReadyResolver<D, P> + ?Sized,
{
fn handle(&self, item: TaskStatus<D, P>, engine: BoxedExecutionEngine) {
(**self).handle(item, engine);
}
}
pub struct FnMutReady<F>(cell::RefCell<F>);
impl<F> FnMutReady<F> {
pub fn new(f: F) -> Self {
Self(cell::RefCell::new(f))
}
}
impl<F, D, P> TaskReadyResolver<D, P> for FnMutReady<F>
where
F: FnMut(TaskStatus<D, P>, BoxedExecutionEngine),
{
fn handle(&self, item: TaskStatus<D, P>, engine: BoxedExecutionEngine) {
let mut mut_fn = self.0.borrow_mut();
(mut_fn)(item, engine);
}
}
pub struct FnReady<F>(F);
impl<F> FnReady<F> {
pub fn new(f: F) -> Self {
Self(f)
}
}
impl<F, D, P> TaskReadyResolver<D, P> for FnReady<F>
where
F: Fn(TaskStatus<D, P>, BoxedExecutionEngine),
{
fn handle(&self, item: TaskStatus<D, P>, engine: BoxedExecutionEngine) {
self.0(item, engine);
}
}
pub struct OnceCache<D, P, T: Iterator<Item = TaskStatus<D, P>>> {
iter: T,
used: Option<()>,
cache: Option<TaskStatus<D, P>>,
}
impl<D, P, T> OnceCache<D, P, T>
where
T: Iterator<Item = TaskStatus<D, P>>,
{
pub fn new(item: T) -> Self {
Self {
iter: item,
cache: None,
used: None,
}
}
pub fn take(&mut self) -> Option<TaskStatus<D, P>> {
self.cache.take()
}
}
impl<D, P, T> Iterator for OnceCache<D, P, T>
where
T: Iterator<Item = TaskStatus<D, P>>,
{
type Item = TaskStatus<D, P>;
fn next(&mut self) -> Option<Self::Item> {
if self.used.is_some() {
return None;
}
match self.iter.next() {
Some(elem) => match elem {
TaskStatus::Spawn(inner) => Some(TaskStatus::Spawn(inner)),
TaskStatus::Delayed(dur) => Some(TaskStatus::Delayed(dur)),
TaskStatus::Pending(dur) => Some(TaskStatus::Pending(dur)),
TaskStatus::Init => Some(TaskStatus::Init),
TaskStatus::Ignore => Some(TaskStatus::Ignore),
TaskStatus::Wait => Some(TaskStatus::Wait),
TaskStatus::Ready(item) => {
self.cache = Some(TaskStatus::Ready(item));
self.used = Some(());
None
}
TaskStatus::Spread(items) => Some(TaskStatus::Spread(items)),
TaskStatus::Depends(signal) => Some(TaskStatus::Depends(signal)),
},
None => None,
}
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum ReadyValue<P> {
Skip,
Inner(P),
}
impl<P> ReadyValue<P> {
pub fn inner(self) -> Option<P> {
match self {
Self::Skip => None,
Self::Inner(inner) => Some(inner),
}
}
}
pub struct ReadyValues<D, P, T: Iterator<Item = TaskStatus<D, P>>> {
iter: T,
}
impl<D, P, T> ReadyValues<D, P, T>
where
T: Iterator<Item = TaskStatus<D, P>>,
{
pub fn new(item: T) -> Self {
Self { iter: item }
}
}
impl<D, P, T> Iterator for ReadyValues<D, P, T>
where
T: Iterator<Item = TaskStatus<D, P>>,
{
type Item = ReadyValue<D>;
fn next(&mut self) -> Option<Self::Item> {
match self.iter.next() {
Some(elem) => match elem {
TaskStatus::Init
| TaskStatus::Spawn(_)
| TaskStatus::Delayed(_)
| TaskStatus::Pending(_)
| TaskStatus::Ignore
| TaskStatus::Wait
| TaskStatus::Depends(_) => Some(ReadyValue::Skip),
TaskStatus::Ready(item) => Some(ReadyValue::Inner(item)),
TaskStatus::Spread(_) => Some(ReadyValue::Skip),
},
None => None,
}
}
}
pub struct UntilTake<D, P, T: Iterator<Item = TaskStatus<D, P>>> {
iter: T,
next: Option<TaskStatus<D, P>>,
}
impl<D, P, T> UntilTake<D, P, T>
where
T: Iterator<Item = TaskStatus<D, P>>,
{
pub fn new(item: T) -> Self {
Self {
iter: item,
next: None,
}
}
pub fn take(&mut self) -> Option<TaskStatus<D, P>> {
self.next.take()
}
}
impl<D, P, T> Iterator for UntilTake<D, P, T>
where
T: Iterator<Item = TaskStatus<D, P>>,
{
type Item = TaskStatus<D, P>;
fn next(&mut self) -> Option<Self::Item> {
if self.next.is_some() {
return None;
}
match self.iter.next() {
Some(elem) => match elem {
TaskStatus::Delayed(dur) => Some(TaskStatus::Delayed(dur)),
TaskStatus::Spawn(inner) => Some(TaskStatus::Spawn(inner)),
TaskStatus::Pending(dur) => Some(TaskStatus::Pending(dur)),
TaskStatus::Init => Some(TaskStatus::Init),
TaskStatus::Ignore => Some(TaskStatus::Ignore),
TaskStatus::Ready(item) => {
self.next = Some(TaskStatus::Ready(item));
None
}
TaskStatus::Wait => Some(TaskStatus::Wait),
TaskStatus::Spread(items) => Some(TaskStatus::Spread(items)),
TaskStatus::Depends(signal) => Some(TaskStatus::Depends(signal)),
},
None => None,
}
}
}
pub struct UntilUnblocked<D, P, T: Iterator<Item = TaskStatus<D, P>>> {
iter: T,
blocked: Option<()>,
}
impl<D, P, T> UntilUnblocked<D, P, T>
where
T: Iterator<Item = TaskStatus<D, P>>,
{
pub fn new(item: T) -> Self {
Self {
iter: item,
blocked: None,
}
}
pub fn reset(&mut self) {
self.blocked.take();
}
}
impl<D, P, T> Iterator for UntilUnblocked<D, P, T>
where
T: Iterator<Item = TaskStatus<D, P>>,
{
type Item = TaskStatus<D, P>;
fn next(&mut self) -> Option<Self::Item> {
if self.blocked.is_some() {
return None;
}
self.iter.next().map(|elem| match elem {
TaskStatus::Delayed(dur) => TaskStatus::Delayed(dur),
TaskStatus::Spawn(inner) => TaskStatus::Spawn(inner),
TaskStatus::Pending(dur) => TaskStatus::Pending(dur),
TaskStatus::Init => TaskStatus::Init,
TaskStatus::Ignore => TaskStatus::Ignore,
TaskStatus::Ready(item) => {
self.blocked = Some(());
TaskStatus::Ready(item)
}
TaskStatus::Wait => TaskStatus::Wait,
TaskStatus::Spread(items) => TaskStatus::Spread(items),
TaskStatus::Depends(signal) => TaskStatus::Depends(signal),
})
}
}
pub enum TaskShortCircuit<D, P> {
Continue(TaskStatus<D, P>),
ReturnAndStop(TaskStatus<D, P>),
Stop,
}