use std::collections::HashSet;
use std::sync::Arc;
use petgraph::graph::NodeIndex;
use crate::core::{Dynamic, Store, TaskContext};
use crate::engine::Handle;
use crate::engine::tracking::{TrackerPtr, TrackerState, Tracking};
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct One<T> {
pub(crate) index: NodeIndex,
_phantom: std::marker::PhantomData<T>,
}
impl<T> One<T> {
pub(crate) fn new(index: NodeIndex) -> Self {
Self {
index,
_phantom: std::marker::PhantomData,
}
}
pub fn index(&self) -> NodeIndex {
self.index
}
}
impl<T> Clone for One<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for One<T> {}
impl<T> Handle for One<T>
where
T: Send + Sync + 'static,
{
type Output<'a> = &'a T;
fn index(&self) -> NodeIndex {
self.index
}
fn downcast<'a>(&self, output: &'a Dynamic) -> (Option<TrackerPtr>, Self::Output<'a>) {
#[allow(clippy::expect_used)] let output = output
.downcast_ref::<T>()
.expect("Type mismatch in dependency resolution");
(None, output)
}
fn is_valid(
&self,
_: &Option<TrackerState>,
_: &Dynamic,
updated: &HashSet<NodeIndex>,
) -> bool {
!updated.contains(&self.index)
}
}
pub(crate) trait TypedCoarse<G: Send + Sync = ()>: Send + Sync {
type Output: Send + Sync + 'static;
fn get_name(&self) -> String;
fn dependencies(&self) -> Vec<NodeIndex>;
fn get_watched(&self) -> Vec<camino::Utf8PathBuf>;
fn execute(
&self,
context: &crate::TaskContext<G>,
runtime: &mut Store,
dependencies: &[Dynamic],
) -> anyhow::Result<(Tracking, Self::Output)>;
fn is_dirty(&self, _: &camino::Utf8Path) -> bool {
false
}
fn is_valid(
&self,
old_tracking: &[Option<TrackerState>],
new_outputs: &[Dynamic],
updated_nodes: &HashSet<NodeIndex>,
) -> bool;
fn requirements(&self) -> Vec<crate::preflight::Requirement> {
vec![]
}
}
pub(crate) trait Coarse<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 get_watched(&self) -> Vec<camino::Utf8PathBuf>;
fn execute(
&self,
context: &TaskContext<G>,
runtime: &mut Store,
dependencies: &[Dynamic],
) -> anyhow::Result<(Tracking, Dynamic)>;
#[inline]
fn is_dirty(&self, _: &camino::Utf8Path) -> bool {
false
}
fn is_valid(
&self,
old_tracking: &[Option<TrackerState>],
new_outputs: &[Dynamic],
updated_nodes: &HashSet<NodeIndex>,
) -> bool;
fn requirements(&self) -> Vec<crate::preflight::Requirement>;
}
impl<G, T> Coarse<G> for T
where
G: Send + Sync,
T: TypedCoarse<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 get_watched(&self) -> Vec<camino::Utf8PathBuf> {
T::get_watched(self)
}
fn execute(
&self,
context: &TaskContext<G>,
runtime: &mut Store,
dependencies: &[Dynamic],
) -> anyhow::Result<(Tracking, Dynamic)> {
let (tracking, output) = T::execute(self, context, runtime, dependencies)?;
Ok((tracking, Arc::new(output)))
}
fn is_dirty(&self, path: &camino::Utf8Path) -> bool {
T::is_dirty(self, path)
}
fn is_valid(
&self,
old_tracking: &[Option<TrackerState>],
new_outputs: &[Dynamic],
updated_nodes: &HashSet<NodeIndex>,
) -> bool {
T::is_valid(self, old_tracking, new_outputs, updated_nodes)
}
fn requirements(&self) -> Vec<crate::preflight::Requirement> {
T::requirements(self)
}
}