use alloc::{boxed::Box, vec::Vec};
use core::{
future::{Future, pending, poll_fn},
pin::Pin,
task::Poll,
};
use crate::application::BoxFuture;
pub struct Task<M> {
pub(crate) futures: Vec<BoxFuture<Option<M>>>,
}
impl<M: 'static> Task<M> {
#[must_use]
pub fn none() -> Self {
Self {
futures: Vec::new(),
}
}
#[must_use]
pub fn perform<F>(fut: F) -> Self
where
F: Future<Output = Option<M>> + 'static,
{
let mut futures = Vec::with_capacity(1);
futures.push(Box::pin(fut) as BoxFuture<Option<M>>);
Self { futures }
}
#[must_use]
pub fn future<F>(fut: F) -> Self
where
F: Future<Output = M> + 'static,
{
Self::perform(async move { Some(fut.await) })
}
#[must_use]
pub fn batch(tasks: impl IntoIterator<Item = Task<M>>) -> Self {
let mut futures: Vec<BoxFuture<Option<M>>> = Vec::new();
for task in tasks {
futures.extend(task.futures);
}
Self { futures }
}
pub(crate) fn is_empty(&self) -> bool {
self.futures.is_empty()
}
pub(crate) fn extend(&mut self, other: Task<M>) {
self.futures.extend(other.futures)
}
pub(crate) async fn next(&mut self) -> Option<M> {
if self.is_empty() {
return pending::<Option<M>>().await;
}
poll_fn(|cx| {
let mut idx = 0;
while idx < self.futures.len() {
match Pin::as_mut(&mut self.futures[idx]).poll(cx) {
Poll::Ready(result) => {
let _ = self.futures.swap_remove(idx);
return Poll::Ready(result);
}
Poll::Pending => idx += 1,
}
}
Poll::Pending
})
.await
}
}
impl<M> Default for Task<M> {
fn default() -> Self {
Self {
futures: Vec::new(),
}
}
}