use std::any::Any;
use std::sync::Arc;
use petgraph::graph::NodeIndex;
use crate::TaskContext;
use crate::importmap::ImportMap;
use crate::loader::Store;
pub(crate) type Dynamic = Arc<dyn Any + Send + Sync>;
#[derive(Clone, Debug)]
pub(crate) struct NodeData {
pub output: Dynamic,
pub importmap: ImportMap,
}
pub(crate) trait TypedTask<G: Send + Sync = ()>: Send + Sync {
type Output: Send + Sync + 'static;
fn get_name(&self) -> String;
fn dependencies(&self) -> Vec<NodeIndex>;
fn execute(
&self,
context: &TaskContext<G>,
runtime: &mut Store,
dependencies: &[Dynamic],
) -> anyhow::Result<Self::Output>;
#[inline]
fn is_dirty(&self, _: &camino::Utf8Path) -> bool {
false
}
}
pub(crate) trait Task<G: Send + Sync = ()>: Send + Sync {
fn get_name(&self) -> String;
fn get_output_type_name(&self) -> &'static str;
fn is_output(&self) -> bool;
fn dependencies(&self) -> Vec<NodeIndex>;
fn execute(
&self,
context: &TaskContext<G>,
runtime: &mut Store,
dependencies: &[Dynamic],
) -> anyhow::Result<Dynamic>;
#[inline]
fn is_dirty(&self, _: &camino::Utf8Path) -> bool {
false
}
}
impl<G, T> Task<G> for T
where
G: Send + Sync,
T: TypedTask<G> + 'static,
{
fn get_name(&self) -> String {
T::get_name(self)
}
fn get_output_type_name(&self) -> &'static str {
std::any::type_name::<T::Output>()
}
fn is_output(&self) -> bool {
use std::any::TypeId;
TypeId::of::<T::Output>() == TypeId::of::<crate::Output>()
|| TypeId::of::<T::Output>() == TypeId::of::<Vec<crate::Output>>()
}
fn dependencies(&self) -> Vec<NodeIndex> {
T::dependencies(self)
}
fn execute(
&self,
context: &TaskContext<G>,
runtime: &mut Store,
dependencies: &[Dynamic],
) -> anyhow::Result<Dynamic> {
Ok(Arc::new(T::execute(self, context, runtime, dependencies)?))
}
fn is_dirty(&self, path: &camino::Utf8Path) -> bool {
T::is_dirty(self, path)
}
}
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct Handle<T> {
pub(crate) index: NodeIndex,
_phantom: std::marker::PhantomData<T>,
}
impl<T> Handle<T> {
pub(crate) fn new(index: NodeIndex) -> Self {
Self {
index,
_phantom: std::marker::PhantomData,
}
}
pub fn index(&self) -> NodeIndex {
self.index
}
}
impl<T> Copy for Handle<T> {}
impl<T> Clone for Handle<T> {
fn clone(&self) -> Self {
*self
}
}
pub trait TaskDependencies {
type Output<'a>;
fn dependencies(&self) -> Vec<NodeIndex>;
fn resolve<'a>(&self, outputs: &'a [Dynamic]) -> Self::Output<'a>;
}
impl TaskDependencies for () {
type Output<'a> = ();
fn dependencies(&self) -> Vec<NodeIndex> {
vec![]
}
fn resolve<'a>(&self, _outputs: &'a [Dynamic]) -> Self::Output<'a> {}
}
impl<T> TaskDependencies for Handle<T>
where
T: Send + Sync + 'static,
{
type Output<'a> = &'a T;
fn dependencies(&self) -> Vec<NodeIndex> {
vec![self.index]
}
fn resolve<'a>(&self, outputs: &'a [Dynamic]) -> Self::Output<'a> {
outputs[0].downcast_ref::<T>().unwrap()
}
}
macro_rules! impl_deps {
($($T:ident),*) => {
#[allow(non_snake_case)]
impl<$($T: Send + Sync + 'static),*> TaskDependencies for ($(Handle<$T>,)*) {
type Output<'a> = ($(&'a $T,)*);
fn dependencies(&self) -> Vec<NodeIndex> {
let ($($T,)*) = self;
vec![$($T.index),*]
}
fn resolve<'a>(&self, outputs: &'a [Dynamic]) -> Self::Output<'a> {
let mut iter = outputs.iter();
($({
let out = iter.next().unwrap();
out.downcast_ref::<$T>().unwrap()
},)*)
}
}
};
}
impl_deps!(A);
impl_deps!(A, B);
impl_deps!(A, B, C);
impl_deps!(A, B, C, D);
impl_deps!(A, B, C, D, E);
impl_deps!(A, B, C, D, E, F);
impl_deps!(A, B, C, D, E, F, G);
impl_deps!(A, B, C, D, E, F, G, H);
impl_deps!(A, B, C, D, E, F, G, H, I);
impl_deps!(A, B, C, D, E, F, G, H, I, J);
impl_deps!(A, B, C, D, E, F, G, H, I, J, K);
impl_deps!(A, B, C, D, E, F, G, H, I, J, K, L);