#![cfg(feature = "multi")]
#![allow(clippy::type_complexity)]
use crate::valtron::multi;
use crate::valtron::FutureTask;
use crate::valtron::ReadyValues;
use crate::valtron::StreamConfig;
use crate::valtron::StreamTask;
use crate::valtron::TaskStatusMapper;
use crate::valtron::ThreadedValue;
use crate::valtron::{
collect_one, collect_result, ExecutionAction, GenericResult, NotificationItem,
NotifyQueueStreamIterator, NotifyRecvIterator, Stream, StreamIterator, TaskIterator,
TaskStatus,
};
use core::future::Future;
use crate::valtron::{DEFAULT_MAX_TURNS, DEFAULT_PARK_DURATION, DEFAULT_WAIT_CYCLE};
use crate::valtron::{InlineSendAction, InlineSendActionBehaviour};
#[must_use]
pub fn initialize_pool(
seed_for_rng: u64,
user_thread_num: Option<usize>,
) -> crate::valtron::multi::PoolGuard {
tracing::debug!("Starting under feature=multi");
multi::initialize_pool(seed_for_rng, user_thread_num)
}
pub fn run_background_job(job: impl FnOnce() + Send + 'static) -> GenericResult<()> {
#[cfg(target_arch = "wasm32")]
{
super::single::run_background_job(job)
}
#[cfg(not(target_arch = "wasm32"))]
{
super::multi::run_background_job(job)
}
}
pub fn execute_as_task<T>(
task: T,
wait_cycle: Option<std::time::Duration>,
) -> GenericResult<DrivenRecvIterator<T>>
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static,
{
tracing::debug!("Executing as a multi-threaded stream in no-wasm with multi=off");
use crate::valtron::multi;
let iter = multi::spawn()
.with_task(task)
.schedule_iter(wait_cycle.unwrap_or(DEFAULT_WAIT_CYCLE))?;
Ok(drive_receiver(iter))
}
pub fn execute<T>(
task: T,
wait_cycle: Option<std::time::Duration>,
) -> GenericResult<DrivenStreamIterator<T>>
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static,
{
tracing::debug!("Executing as a multi-threaded stream in no-wasm");
let iter = multi::spawn().with_task(task).stream_iter_with_config(
wait_cycle.unwrap_or(DEFAULT_PARK_DURATION),
DEFAULT_MAX_TURNS,
)?;
Ok(drive_stream(iter))
}
pub fn execute_with_config<T>(
task: T,
config: StreamConfig,
) -> GenericResult<DrivenStreamIterator<T>>
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static,
{
use crate::valtron::multi;
tracing::debug!("Executing as a multi-threaded stream in no-wasm with config");
let iter = multi::spawn()
.with_task(task)
.stream_iter_with_config(config.park_duration, config.max_turns)?;
Ok(drive_stream(iter))
}
pub fn send<T>(task: T) -> GenericResult<()>
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static,
{
tracing::debug!("Executing as a multi-threaded stream in no-wasm");
multi::spawn().with_task(task).schedule()?;
Ok(())
}
pub fn run_future_iter<F, Fut, I, T, E>(
future_fn: F,
queue_size: Option<usize>,
backpressure_sleep: Option<std::time::Duration>,
) -> crate::valtron::GenericResult<impl Iterator<Item = ThreadedValue<T, E>>>
where
F: FnOnce() -> Fut + Send + 'static,
Fut: Future<Output = Result<I, E>> + 'static,
I: Iterator<Item = Result<T, E>> + 'static,
T: Send + 'static,
E: Send + 'static,
{
use crate::valtron::ThreadedIterFuture;
tracing::debug!("Executing as a multi-threaded future iterator");
let threaded = ThreadedIterFuture::with_backpressure_sleep(
future_fn,
queue_size.unwrap_or(16),
backpressure_sleep.or(Some(std::time::Duration::from_millis(10))),
);
threaded.execute()
}
pub fn run_future<F>(future: F) -> crate::valtron::GenericResult<Vec<F::Output>>
where
F: Future + Send + 'static,
F::Output: Send + 'static,
{
let task = FutureTask::new(future);
let iter: DrivenRecvIterator<FutureTask<F>> = execute_as_task(task, None)?;
let values_iter = ReadyValues::new(iter);
let values: Vec<F::Output> = values_iter
.filter_map(super::super::task::ReadyValue::inner)
.collect();
Ok(values)
}
pub fn from_stream<S>(stream: S) -> StreamTask<S>
where
S: futures_core::Stream + Send + 'static,
S::Item: Send + 'static,
{
StreamTask::new(stream)
}
pub fn from_future<F>(future: F) -> FutureTask<F>
where
F: Future + Send + 'static,
F::Output: Send + 'static,
{
FutureTask::new(future)
}
pub fn drive_future<F>(future: F) -> DrivenTaskIterator<FutureTask<F>>
where
F: Future + Send + 'static,
F::Output: Send + 'static,
{
drive_iterator(crate::valtron::from_future(future))
}
pub fn drive_future_stream<S>(stream: S) -> DrivenTaskIterator<StreamTask<S>>
where
S: futures_core::Stream + Send + 'static,
S::Item: Send + 'static,
{
drive_iterator(crate::valtron::from_stream(stream))
}
pub fn inlined_mapped_task<Done, Pending, Action, Task, Mapper>(
behaviour: InlineSendActionBehaviour,
mappers: Vec<Mapper>,
task: Task,
wait_cycle: std::time::Duration,
) -> (
InlineSendAction<Done, Pending, Action, Task, Mapper>,
DrivenRecvIterator<Task>,
)
where
Done: Send + 'static,
Pending: Send + 'static,
Action: ExecutionAction + Send + 'static,
Mapper: TaskStatusMapper<Done, Pending, Action> + Send + 'static,
Task: TaskIterator<Pending = Pending, Ready = Done, Spawner = Action> + Send + 'static,
{
let (task_action, task_receiver) = InlineSendAction::new(behaviour, mappers, task, wait_cycle);
(task_action, drive_receiver(task_receiver))
}
pub fn inlined_task<Done, Pending, Action, Task>(
behaviour: InlineSendActionBehaviour,
mappers: Vec<Box<dyn TaskStatusMapper<Done, Pending, Action> + Send + 'static>>,
task: Task,
wait_cycle: std::time::Duration,
) -> (
InlineSendAction<
Done,
Pending,
Action,
Task,
Box<dyn TaskStatusMapper<Done, Pending, Action> + Send + 'static>,
>,
DrivenRecvIterator<Task>,
)
where
Done: Send + 'static,
Pending: Send + 'static,
Action: ExecutionAction + Send + 'static,
Task: TaskIterator<Pending = Pending, Ready = Done, Spawner = Action> + Send + 'static,
{
let (task_action, task_receiver) =
InlineSendAction::boxed_mapper(behaviour, mappers, task, wait_cycle);
(task_action, drive_receiver(task_receiver))
}
#[must_use]
#[tracing::instrument(skip(incoming))]
pub fn drive_iterator<T>(incoming: T) -> DrivenTaskIterator<T>
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static,
{
DrivenTaskIterator::new(incoming)
}
#[must_use]
#[tracing::instrument(skip(incoming))]
pub fn drive_receiver<T>(
incoming: NotifyRecvIterator<TaskStatus<T::Ready, T::Pending, T::Spawner>>,
) -> DrivenRecvIterator<T>
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static,
{
DrivenRecvIterator::new(incoming)
}
#[must_use]
#[tracing::instrument(skip(incoming))]
pub fn drive_stream<T>(
incoming: NotifyQueueStreamIterator<T::Ready, T::Pending>,
) -> DrivenStreamIterator<T>
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static,
{
DrivenStreamIterator::new(incoming)
}
pub fn sync_collect_one<T>(task: T) -> GenericResult<T::Ready>
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static,
{
let stream = execute(task, None)?;
collect_one(stream).ok_or_else(|| "sync_collect_one: stream produced no result".into())
}
pub fn sync_one<T>(task: T) -> GenericResult<Vec<T::Ready>>
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static,
{
let stream = execute(task, None)?;
Ok(collect_result(stream))
}
pub fn sync_all<T>(tasks: Vec<T>) -> GenericResult<Vec<T::Ready>>
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static,
{
if tasks.is_empty() {
return Err("empty tasks not allowed".into());
}
let mut stream = execute_collect_all(tasks, None)?;
stream
.find_map(|s| match s {
Stream::Next(v) => Some(v),
_ => None,
})
.ok_or_else(|| "sync_all: no results produced by execute_collect_all".into())
}
pub fn execute_collect_all<T>(
tasks: Vec<T>,
wait_cycle: Option<std::time::Duration>,
) -> GenericResult<CollectAllTaskStream<T>>
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static,
{
let streams: Vec<DrivenStreamIterator<T>> = tasks
.into_iter()
.map(|t| execute(t, wait_cycle))
.collect::<GenericResult<_>>()?;
Ok(CollectAllTaskStream::new(streams))
}
pub struct DrivenTaskIterator<T>(Option<T>)
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static;
impl<T> DrivenTaskIterator<T>
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static,
{
pub fn new(task_iterator: T) -> Self {
Self(Some(task_iterator))
}
}
unsafe impl<T> Send for DrivenTaskIterator<T>
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static,
{
}
impl<T> Iterator for DrivenTaskIterator<T>
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static,
{
type Item = TaskStatus<T::Ready, T::Pending, T::Spawner>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(mut task_iterator) = self.0.take() {
tracing::trace!("Run: run_until_next_state");
let next_value = task_iterator.next_status();
if next_value.is_some() {
self.0.replace(task_iterator);
}
next_value
} else {
None
}
}
}
pub struct DrivenStreamIterator<T>(Option<NotifyQueueStreamIterator<T::Ready, T::Pending>>)
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static;
impl<T> DrivenStreamIterator<T>
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static,
{
#[must_use]
pub fn new(task_iterator: NotifyQueueStreamIterator<T::Ready, T::Pending>) -> Self {
Self(Some(task_iterator))
}
pub fn is_empty(&self) -> bool {
match &self.0 {
Some(inner) => inner.is_empty(),
None => true,
}
}
}
unsafe impl<T> Send for DrivenStreamIterator<T>
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static,
{
}
impl<T> Iterator for DrivenStreamIterator<T>
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static,
{
type Item = Stream<T::Ready, T::Pending>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(mut task_iterator) = self.0.take() {
tracing::trace!("Run: run_until_next_state");
let next_value = task_iterator.next();
if next_value.is_some() {
self.0.replace(task_iterator);
}
next_value
} else {
None
}
}
}
pub struct DrivenRecvIterator<T>(
Option<NotifyRecvIterator<TaskStatus<T::Ready, T::Pending, T::Spawner>>>,
)
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static;
impl<T> DrivenRecvIterator<T>
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static,
{
#[must_use]
pub fn new(
task_iterator: NotifyRecvIterator<TaskStatus<T::Ready, T::Pending, T::Spawner>>,
) -> Self {
Self(Some(task_iterator))
}
}
unsafe impl<T> Send for DrivenRecvIterator<T>
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static,
{
}
impl<T> Iterator for DrivenRecvIterator<T>
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static,
{
type Item = TaskStatus<T::Ready, T::Pending, T::Spawner>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(mut task_iterator) = self.0.take() {
tracing::trace!("Run: run_until_next_state");
let next_value = task_iterator.next();
match next_value {
Some(NotificationItem::Ready(status)) => {
self.0.replace(task_iterator);
Some(status)
}
Some(NotificationItem::None) => {
self.0.replace(task_iterator);
Some(TaskStatus::Wait)
}
None => None, }
} else {
None
}
}
}
pub struct CollectAllTaskStream<T>
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static,
{
sources: Vec<DrivenStreamIterator<T>>,
collected: Vec<T::Ready>,
done: bool,
current_index: usize,
}
impl<T> CollectAllTaskStream<T>
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static,
{
#[must_use]
pub fn new(sources: Vec<DrivenStreamIterator<T>>) -> Self {
Self {
sources,
collected: Vec::new(),
done: false,
current_index: 0,
}
}
}
impl<T> Iterator for CollectAllTaskStream<T>
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static,
{
type Item = Stream<Vec<T::Ready>, usize>;
fn next(&mut self) -> Option<Self::Item> {
if self.done {
return None;
}
if self.sources.is_empty() {
self.done = true;
if self.collected.is_empty() {
return None;
}
return Some(Stream::Next(std::mem::take(&mut self.collected)));
}
let idx = self.current_index;
match self.sources[idx].next() {
Some(Stream::Next(value)) => {
self.collected.push(value);
self.current_index = (self.current_index + 1) % self.sources.len();
Some(Stream::Pending(self.sources.len()))
}
Some(Stream::Pending(_)) => {
self.current_index = (self.current_index + 1) % self.sources.len();
Some(Stream::Pending(self.sources.len()))
}
Some(Stream::Delayed(d)) => {
self.current_index = (self.current_index + 1) % self.sources.len();
Some(Stream::Delayed(d))
}
Some(Stream::Init) => {
self.current_index = (self.current_index + 1) % self.sources.len();
Some(Stream::Pending(self.sources.len()))
}
Some(Stream::Ignore) => {
self.current_index = (self.current_index + 1) % self.sources.len();
Some(Stream::Pending(self.sources.len()))
}
Some(Stream::Wait) => {
self.current_index = (self.current_index + 1) % self.sources.len();
Some(Stream::Pending(self.sources.len()))
}
Some(Stream::Spread(items)) => {
for item in items {
if let crate::valtron::streams::StreamSpread::Done(d) = item {
self.collected.push(d);
}
}
self.current_index = (self.current_index + 1) % self.sources.len();
Some(Stream::Pending(self.sources.len()))
}
None => {
self.sources.swap_remove(idx);
if self.current_index >= self.sources.len() && !self.sources.is_empty() {
self.current_index = 0;
}
if self.sources.is_empty() {
self.done = true;
if self.collected.is_empty() {
return None;
}
Some(Stream::Next(std::mem::take(&mut self.collected)))
} else {
Some(Stream::Pending(self.sources.len()))
}
}
}
}
}
pub fn collect_all_streams<S>(streams: Vec<S>) -> CollectAllStreams<S>
where
S: StreamIterator<P = usize> + Send + 'static,
S::D: Send + 'static,
{
CollectAllStreams::new(streams)
}
pub fn one_shot<D, P>(value: D) -> OneShotStream<D, P>
where
D: Send + 'static,
P: Send + 'static,
{
OneShotStream {
value: Some(value),
_phantom: std::marker::PhantomData,
}
}
pub struct OneShotStream<D, P> {
value: Option<D>,
_phantom: std::marker::PhantomData<P>,
}
impl<D, P> Iterator for OneShotStream<D, P>
where
D: Send + 'static,
P: Send + 'static,
{
type Item = Stream<D, P>;
fn next(&mut self) -> Option<Self::Item> {
self.value.take().map(Stream::Next)
}
}
pub struct CollectAllStreams<S>
where
S: StreamIterator<P = usize> + Send + 'static,
S::D: Send + 'static,
{
sources: Vec<S>,
collected: Vec<S::D>,
done: bool,
current_index: usize,
}
impl<S> CollectAllStreams<S>
where
S: StreamIterator<P = usize> + Send + 'static,
S::D: Send + 'static,
{
#[must_use]
pub fn new(sources: Vec<S>) -> Self {
Self {
sources,
collected: Vec::new(),
done: false,
current_index: 0,
}
}
}
impl<S> Iterator for CollectAllStreams<S>
where
S: StreamIterator<P = usize> + Send + 'static,
S::D: Send + 'static,
{
type Item = Stream<Vec<S::D>, usize>;
fn next(&mut self) -> Option<Self::Item> {
if self.done {
return None;
}
if self.sources.is_empty() {
self.done = true;
if self.collected.is_empty() {
return None;
}
return Some(Stream::Next(std::mem::take(&mut self.collected)));
}
let mut exhausted_indices = Vec::new();
for _ in 0..self.sources.len() {
let idx = self.current_index;
match self.sources[idx].next() {
Some(Stream::Next(value)) => {
self.collected.push(value);
self.current_index = (self.current_index + 1) % self.sources.len();
return Some(Stream::Pending(self.sources.len()));
}
Some(Stream::Pending(_)) => {
self.current_index = (self.current_index + 1) % self.sources.len();
return Some(Stream::Pending(self.sources.len()));
}
Some(Stream::Delayed(d)) => {
self.current_index = (self.current_index + 1) % self.sources.len();
return Some(Stream::Delayed(d));
}
Some(Stream::Init) => {
self.current_index = (self.current_index + 1) % self.sources.len();
return Some(Stream::Pending(self.sources.len()));
}
Some(Stream::Ignore) => {
self.current_index = (self.current_index + 1) % self.sources.len();
}
Some(Stream::Wait) => {
self.current_index = (self.current_index + 1) % self.sources.len();
}
Some(Stream::Spread(items)) => {
for item in items {
if let crate::valtron::streams::StreamSpread::Done(d) = item {
self.collected.push(d);
}
}
self.current_index = (self.current_index + 1) % self.sources.len();
return Some(Stream::Pending(self.sources.len()));
}
None => {
exhausted_indices.push(idx);
self.current_index = (self.current_index + 1) % self.sources.len();
}
}
}
exhausted_indices.sort_by(|a, b| b.cmp(a));
for idx in exhausted_indices {
self.sources.swap_remove(idx);
}
if !self.sources.is_empty() && self.current_index >= self.sources.len() {
self.current_index = 0;
}
if self.sources.is_empty() {
self.done = true;
if self.collected.is_empty() {
return None;
}
return Some(Stream::Next(std::mem::take(&mut self.collected)));
}
Some(Stream::Pending(self.sources.len()))
}
}
pub fn execute_map_all<T, F, O>(
tasks: Vec<T>,
mapper: F,
wait_cycle: Option<std::time::Duration>,
) -> GenericResult<MapAllDoneStream<T, F, O>>
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static,
F: Fn(Vec<T::Ready>) -> O + Send + 'static,
O: Send + 'static,
{
let streams: Vec<DrivenStreamIterator<T>> = tasks
.into_iter()
.map(|t| execute(t, wait_cycle))
.collect::<GenericResult<_>>()?;
Ok(MapAllDoneStream::new(streams, mapper))
}
pub struct MapAllDoneStream<T, F, O>
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static,
{
sources: Vec<DrivenStreamIterator<T>>,
mapper: F,
buffer: Vec<Option<T::Ready>>,
done: bool,
_phantom: std::marker::PhantomData<O>,
}
impl<T, F, O> MapAllDoneStream<T, F, O>
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static,
{
pub fn new(sources: Vec<DrivenStreamIterator<T>>, mapper: F) -> Self {
let len = sources.len();
Self {
sources,
mapper,
buffer: (0..len).map(|_| None).collect(),
done: false,
_phantom: std::marker::PhantomData,
}
}
}
impl<T, F, O> Iterator for MapAllDoneStream<T, F, O>
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static,
F: Fn(Vec<T::Ready>) -> O,
{
type Item = Stream<O, usize>;
fn next(&mut self) -> Option<Self::Item> {
if self.done {
return None;
}
let mut all_done = true;
let mut has_pending = false;
let mut max_delayed: Option<std::time::Duration> = None;
for (i, source) in self.sources.iter_mut().enumerate() {
if self.buffer[i].is_some() {
continue; }
match source.next() {
Some(Stream::Next(value)) => {
self.buffer[i] = Some(value);
}
Some(Stream::Pending(_)) => {
all_done = false;
has_pending = true;
}
Some(Stream::Delayed(d)) => {
all_done = false;
max_delayed = Some(match max_delayed {
Some(current) => current.max(d),
None => d,
});
}
Some(Stream::Init) => {
all_done = false;
}
Some(Stream::Ignore) => {
all_done = false;
}
Some(Stream::Wait) => {
all_done = false;
}
Some(Stream::Spread(values)) => {
if let Some(last) = values.into_iter().find_map(|item| match item {
crate::valtron::streams::StreamSpread::Done(d) => Some(d),
_ => None,
}) {
self.buffer[i] = Some(last);
}
all_done = false;
has_pending = true;
}
None => {
}
}
}
if self.buffer.iter().all(std::option::Option::is_some) {
self.done = true;
let values: Vec<T::Ready> = self.buffer.drain(..).flatten().collect();
let result = (self.mapper)(values);
return Some(Stream::Next(result));
}
if all_done {
self.done = true;
return None;
}
if let Some(delay) = max_delayed {
Some(Stream::Delayed(delay))
} else if has_pending {
let collected: usize = self.buffer.iter().filter(|x| x.is_some()).count();
Some(Stream::Pending(collected))
} else {
Some(Stream::Init)
}
}
}
pub fn execute_map_all_pending_and_done<T, F, O, R>(
tasks: Vec<T>,
mapper: F,
wait_cycle: Option<std::time::Duration>,
) -> GenericResult<MapAllPendingAndDoneStream<T, F, O, R>>
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static,
F: Fn(Vec<Stream<T::Ready, T::Pending>>) -> Vec<Stream<O, R>> + Send + 'static,
O: Send + 'static,
R: Send + 'static,
{
let streams: Vec<DrivenStreamIterator<T>> = tasks
.into_iter()
.map(|t| execute(t, wait_cycle))
.collect::<GenericResult<_>>()?;
Ok(MapAllPendingAndDoneStream::new(streams, mapper))
}
pub struct MapAllPendingAndDoneStream<T, F, O, R>
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static,
{
sources: Vec<DrivenStreamIterator<T>>,
mapper: F,
done: bool,
_phantom: std::marker::PhantomData<(O, R)>,
}
impl<T, F, O, R> MapAllPendingAndDoneStream<T, F, O, R>
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static,
{
pub fn new(sources: Vec<DrivenStreamIterator<T>>, mapper: F) -> Self {
Self {
sources,
mapper,
done: false,
_phantom: std::marker::PhantomData,
}
}
}
impl<T, F, O, R> Iterator for MapAllPendingAndDoneStream<T, F, O, R>
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static,
F: Fn(Vec<Stream<T::Ready, T::Pending>>) -> Vec<Stream<O, R>>,
O: Send + 'static,
R: Send + 'static,
{
type Item = Stream<Vec<Stream<O, R>>, ()>;
fn next(&mut self) -> Option<Self::Item> {
if self.done {
return None;
}
let mut states: Vec<Stream<T::Ready, T::Pending>> = Vec::with_capacity(self.sources.len());
for source in &mut self.sources {
if let Some(state) = source.next() {
states.push(state);
}
}
if states.is_empty() {
self.done = true;
return None;
}
Some(Stream::Next((self.mapper)(states)))
}
}
#[cfg(feature = "multi")]
pub fn execute_collect_next_from_all<T>(
tasks: Vec<T>,
wait_cycle: Option<std::time::Duration>,
) -> GenericResult<CollectNextFromAllStream<T>>
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static,
{
let streams: Vec<DrivenStreamIterator<T>> = tasks
.into_iter()
.map(|t| execute(t, wait_cycle))
.collect::<GenericResult<_>>()?;
Ok(CollectNextFromAllStream::new(streams))
}
pub struct CollectNextFromAllStream<T>
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static,
{
sources: Vec<DrivenStreamIterator<T>>,
current_index: usize,
_phantom: std::marker::PhantomData<T>,
}
impl<T> CollectNextFromAllStream<T>
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static,
{
#[must_use]
pub fn new(sources: Vec<DrivenStreamIterator<T>>) -> Self {
Self {
sources,
current_index: 0,
_phantom: std::marker::PhantomData,
}
}
}
impl<T> Iterator for CollectNextFromAllStream<T>
where
T: TaskIterator + Send + 'static,
T::Ready: Send + 'static,
T::Pending: Send + 'static,
T::Spawner: ExecutionAction + Send + 'static,
{
type Item = Stream<T::Ready, usize>;
fn next(&mut self) -> Option<Self::Item> {
if self.sources.is_empty() {
return None;
}
let mut exhausted_indices = Vec::new();
for _ in 0..self.sources.len() {
let idx = self.current_index;
match self.sources[idx].next() {
Some(Stream::Next(value)) => {
self.current_index = (self.current_index + 1) % self.sources.len();
return Some(Stream::Next(value));
}
Some(Stream::Pending(_)) => {
self.current_index = (self.current_index + 1) % self.sources.len();
return Some(Stream::Pending(self.sources.len()));
}
Some(Stream::Delayed(d)) => {
self.current_index = (self.current_index + 1) % self.sources.len();
return Some(Stream::Delayed(d));
}
Some(Stream::Init) => {
self.current_index = (self.current_index + 1) % self.sources.len();
return Some(Stream::Pending(self.sources.len()));
}
Some(Stream::Ignore) => {
self.current_index = (self.current_index + 1) % self.sources.len();
}
Some(Stream::Wait) => {
self.current_index = (self.current_index + 1) % self.sources.len();
}
Some(Stream::Spread(items)) => {
self.current_index = (self.current_index + 1) % self.sources.len();
for item in items {
if let crate::valtron::streams::StreamSpread::Done(first) = item {
return Some(Stream::Next(first));
}
}
}
None => {
exhausted_indices.push(idx);
self.current_index = (self.current_index + 1) % self.sources.len();
}
}
}
exhausted_indices.sort_by(|a, b| b.cmp(a));
for idx in exhausted_indices {
self.sources.swap_remove(idx);
}
if !self.sources.is_empty() && self.current_index >= self.sources.len() {
self.current_index = 0;
}
if self.sources.is_empty() {
return None;
}
Some(Stream::Pending(self.sources.len()))
}
}
pub fn schedule_future<T, E, F>(
future: F,
) -> GenericResult<impl Iterator<Item = Stream<Result<T, E>, ()>> + Send + 'static>
where
F: Future<Output = Result<T, E>> + Send + 'static,
F::Output: Send + 'static,
T: Send + 'static,
E: Send + 'static,
{
let task = from_future(future);
execute(task, None).map(|stream| {
stream.map(|item| match item {
Stream::Next(result) => Stream::Next(result),
Stream::Pending(_) => Stream::Pending(()),
Stream::Init => Stream::Init,
Stream::Ignore => Stream::Ignore,
Stream::Wait => Stream::Wait,
Stream::Delayed(d) => Stream::Delayed(d),
Stream::Spread(items) => Stream::Spread(items.into_iter().map(|item| {
match item {
crate::valtron::streams::StreamSpread::Done(result) => {
crate::valtron::streams::StreamSpread::Done(result)
}
crate::valtron::streams::StreamSpread::Pending(_) => {
crate::valtron::streams::StreamSpread::Pending(())
}
}
}).collect()),
})
})
}
pub fn exec_future<T, E, F>(future: F) -> GenericResult<Result<T, E>>
where
F: Future<Output = Result<T, E>> + Send + 'static,
F::Output: Send + 'static,
T: Send + 'static,
E: Send + 'static,
{
let task = from_future(future);
let stream = execute(task, None)?;
let result: Option<Result<T, E>> = collect_one(stream);
match result {
Some(Ok(v)) => Ok(Ok(v)),
Some(Err(e)) => Ok(Err(e)),
None => Err("no result from future execution".into()),
}
}