use crate::{
executor::Executor,
modules::{
gather::{Access, Gather, GatherLeaf, access},
handle_kind::HandleKind,
task_handle::TaskHandle,
},
};
use std::sync::Arc;
pub(crate) mod sealed {
pub trait Sealed {}
}
#[diagnostic::on_unimplemented(
message = "`{Self}` isn't a set of task handles",
label = "not a set of handles",
note = "a set is a handle, a tuple of up to 12 sets (nest them for more), an array of sets, or a `Vec` of sets"
)]
#[allow(private_bounds, private_interfaces)]
pub trait HandleSet: sealed::Sealed + Send + Sized + 'static {
type Output: Send + 'static;
#[doc(hidden)]
type Slots: Send + 'static;
#[doc(hidden)]
fn slots(&self) -> Self::Slots;
#[doc(hidden)]
fn filled(slots: &Self::Slots) -> bool;
#[doc(hidden)]
fn assemble(slots: &mut Self::Slots) -> Self::Output;
#[doc(hidden)]
fn link<R>(
self,
gather: &Arc<Gather<R>>,
access: Access<R::Slots, Self::Slots>,
held: &mut Vec<Box<dyn Send>>,
) where
R: HandleSet;
}
impl<U, W> sealed::Sealed for TaskHandle<U, W> where W: HandleKind {}
impl<H> sealed::Sealed for Vec<H> {}
impl<H, const N: usize> sealed::Sealed for [H; N] {}
impl<U, W> HandleSet for TaskHandle<U, W>
where
U: Clone + Send + 'static,
W: HandleKind,
{
type Output = U;
type Slots = Option<U>;
#[inline(always)]
fn slots(&self) -> Self::Slots {
None
}
#[inline(always)]
fn filled(slots: &Self::Slots) -> bool {
slots.is_some()
}
fn assemble(slots: &mut Self::Slots) -> Self::Output {
slots
.take()
.expect("a set is only assembled once every slot is full")
}
fn link<R>(
self,
gather: &Arc<Gather<R>>,
access: Access<R::Slots, Self::Slots>,
held: &mut Vec<Box<dyn Send>>,
) where
R: HandleSet,
{
gather.add_leaf();
Executor::forward(
self.id(),
Box::new(GatherLeaf::<R, U>::new(Arc::clone(gather), access)),
);
held.push(Box::new(self.into_plain()));
}
}
impl<H> HandleSet for Vec<H>
where
H: HandleSet,
{
type Output = Vec<H::Output>;
type Slots = Vec<H::Slots>;
fn slots(&self) -> Self::Slots {
self.iter().map(H::slots).collect()
}
fn filled(slots: &Self::Slots) -> bool {
slots.iter().all(H::filled)
}
fn assemble(slots: &mut Self::Slots) -> Self::Output {
slots.iter_mut().map(H::assemble).collect()
}
fn link<R>(
self,
gather: &Arc<Gather<R>>,
outer: Access<R::Slots, Self::Slots>,
held: &mut Vec<Box<dyn Send>>,
) where
R: HandleSet,
{
for (index, set) in self.into_iter().enumerate() {
let outer = Arc::clone(&outer);
set.link(
gather,
access(move |root: &mut R::Slots| &mut outer(root)[index]),
held,
);
}
}
}
impl<H, const N: usize> HandleSet for [H; N]
where
H: HandleSet,
{
type Output = [H::Output; N];
type Slots = [H::Slots; N];
fn slots(&self) -> Self::Slots {
std::array::from_fn(|index| self[index].slots())
}
fn filled(slots: &Self::Slots) -> bool {
slots.iter().all(H::filled)
}
fn assemble(slots: &mut Self::Slots) -> Self::Output {
std::array::from_fn(|index| H::assemble(&mut slots[index]))
}
fn link<R>(
self,
gather: &Arc<Gather<R>>,
outer: Access<R::Slots, Self::Slots>,
held: &mut Vec<Box<dyn Send>>,
) where
R: HandleSet,
{
for (index, set) in self.into_iter().enumerate() {
let outer = Arc::clone(&outer);
set.link(
gather,
access(move |root: &mut R::Slots| &mut outer(root)[index]),
held,
);
}
}
}