mod coarse;
mod fine;
mod node;
mod runner;
mod tracking;
use std::collections::{BTreeMap, HashSet};
use std::sync::Arc;
use petgraph::graph::NodeIndex;
use crate::core::{ArcStr, Dynamic, Hash32};
pub(crate) use coarse::TypedCoarse;
pub(crate) use fine::TypedFine;
pub(crate) use node::{NodeGather, NodeMap, NodeScatter};
#[cfg(feature = "live")]
pub(crate) use runner::watch;
pub(crate) use runner::{TaskExecution, run_once_parallel, run_tasks_parallel};
pub(crate) use tracking::{TrackerPtr, TrackerState, Tracking};
pub use coarse::One;
pub use fine::Many;
pub use runner::Diagnostics;
pub use tracking::Tracker;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Provenance(pub(crate) Hash32);
#[derive(Debug)]
pub(crate) struct Map<T> {
pub(crate) map: BTreeMap<ArcStr, (T, Provenance)>,
pub(crate) dirty: bool,
}
pub trait Handle: Copy + Send + Sync {
type Output<'a>;
fn index(&self) -> NodeIndex;
fn downcast<'a>(&self, output: &'a Dynamic) -> (Option<TrackerPtr>, Self::Output<'a>);
fn is_valid(
&self,
old_tracking: &Option<TrackerState>,
new_output: &Dynamic,
updated_nodes: &HashSet<NodeIndex>,
) -> bool;
}
pub enum Task<G> {
C(Arc<dyn coarse::Coarse<G>>),
F(Arc<dyn fine::Fine<G>>),
}
impl<G> Task<G>
where
G: Send + Sync,
{
pub(crate) fn name(&self) -> String {
match self {
Task::C(task) => task.get_name(),
Task::F(task) => task.get_name(),
}
}
pub(crate) fn dependencies(&self) -> Vec<NodeIndex> {
match self {
Task::C(task) => task.dependencies(),
Task::F(task) => task.dependencies(),
}
}
pub(crate) fn watched(&self) -> Vec<camino::Utf8PathBuf> {
match self {
Task::C(task) => task.get_watched(),
Task::F(task) => task.get_watched(),
}
}
pub(crate) fn is_output(&self) -> bool {
match self {
Task::C(task) => task.is_output(),
Task::F(task) => task.is_output(),
}
}
pub(crate) fn type_name_output(&self) -> &'static str {
match self {
Task::C(task) => task.get_output_type_name(),
Task::F(task) => task.get_output_type_name(),
}
}
pub(crate) fn is_dirty(&self, path: &camino::Utf8Path) -> bool {
match self {
Task::C(task) => task.is_dirty(path),
Task::F(task) => task.is_dirty(path),
}
}
pub(crate) fn is_valid(
&self,
old_tracking: &[Option<TrackerState>],
new_outputs: &[Dynamic],
updated_nodes: &HashSet<NodeIndex>,
) -> bool {
match self {
Task::C(task) => task.is_valid(old_tracking, new_outputs, updated_nodes),
Task::F(task) => task.is_valid(old_tracking, new_outputs, updated_nodes),
}
}
}
impl<G> Clone for Task<G> {
fn clone(&self) -> Self {
match self {
Task::C(task) => Task::C(task.clone()),
Task::F(task) => Task::F(task.clone()),
}
}
}
pub trait Dependencies {
type Output<'a>;
fn dependencies(&self) -> Vec<NodeIndex>;
fn resolve<'a>(&self, outputs: &'a [Dynamic]) -> (Tracking, Self::Output<'a>);
fn is_valid(
&self,
old_tracking: &[Option<TrackerState>],
new_outputs: &[Dynamic],
updated_nodes: &HashSet<NodeIndex>,
) -> bool;
}
impl Dependencies for () {
type Output<'a> = ();
fn dependencies(&self) -> Vec<NodeIndex> {
vec![]
}
fn resolve<'a>(&self, _: &'a [Dynamic]) -> (Tracking, Self::Output<'a>) {
(Tracking::default(), ())
}
fn is_valid(&self, _: &[Option<TrackerState>], _: &[Dynamic], _: &HashSet<NodeIndex>) -> bool {
true
}
}
impl<H> Dependencies for H
where
H: Handle,
{
type Output<'a> = H::Output<'a>;
fn dependencies(&self) -> Vec<NodeIndex> {
vec![Handle::index(self)]
}
fn resolve<'a>(&self, outputs: &'a [Dynamic]) -> (Tracking, Self::Output<'a>) {
let mut tracking = Tracking::default();
let (tracker_ptr, output) = self.downcast(&outputs[0]);
tracking.edges.push(tracker_ptr);
(tracking, output)
}
fn is_valid(
&self,
old_tracking: &[Option<TrackerState>],
new_outputs: &[Dynamic],
updated_nodes: &HashSet<NodeIndex>,
) -> bool {
self.is_valid(&old_tracking[0], &new_outputs[0], updated_nodes)
}
}
impl<H> Dependencies for Vec<H>
where
H: Handle,
{
type Output<'a> = Vec<H::Output<'a>>;
fn dependencies(&self) -> Vec<NodeIndex> {
self.iter().map(|h| h.index()).collect()
}
fn resolve<'a>(&self, outputs: &'a [Dynamic]) -> (Tracking, Self::Output<'a>) {
let mut tracking = Tracking::default();
let mut result = Vec::with_capacity(self.len());
for (handle, output) in self.iter().zip(outputs) {
let (tracker_ptr, item) = handle.downcast(output);
tracking.edges.push(tracker_ptr);
result.push(item);
}
(tracking, result)
}
fn is_valid(
&self,
old_tracking: &[Option<TrackerState>],
new_outputs: &[Dynamic],
updated_nodes: &HashSet<NodeIndex>,
) -> bool {
self.iter()
.zip(old_tracking.iter())
.zip(new_outputs.iter())
.all(|((handle, tracking), output)| handle.is_valid(tracking, output, updated_nodes))
}
}
macro_rules! impl_deps {
($($D:ident),*) => {
#[allow(non_snake_case)]
impl<$($D),*> Dependencies for ($($D,)*)
where
$($D: Handle),* {
type Output<'a> = ($($D::Output<'a>,)*);
fn dependencies(&self) -> Vec<NodeIndex> {
let ($($D,)*) = self;
vec![$(Handle::index($D),)*]
}
fn resolve<'a>(&self, outputs: &'a [Dynamic]) -> (Tracking, Self::Output<'a>) {
let mut tracking = Tracking::default();
let ($($D,)*) = self;
let mut iter = outputs.iter();
let result = ($({
let out = iter.next().unwrap();
let (tracker_ptr, item) = $D.downcast(out);
tracking.edges.push(tracker_ptr);
item
},)*);
(tracking, result)
}
fn is_valid(
&self,
old_tracking: &[Option<TrackerState>],
new_outputs: &[Dynamic],
updated_nodes: &HashSet<NodeIndex>,
) -> bool {
let ($($D,)*) = self;
let mut tracking_iter = old_tracking.iter();
let mut output_iter = new_outputs.iter();
$(
if !$D.is_valid(tracking_iter.next().unwrap(), output_iter.next().unwrap(), updated_nodes) {
return false;
}
)*
true
}
}
};
}
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);