use crate::{Graph, GraphError, GraphResult, NodeId, OutputKey, ResourceKey};
use std::collections::BTreeMap;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FullRecomputeCheck {
pub checked_derived: Vec<NodeId>,
pub checked_collections: Vec<NodeId>,
pub checked_resources: Vec<ResourceKey>,
pub checked_outputs: Vec<OutputKey>,
}
impl<C, O: Clone> Graph<C, O> {
pub fn full_recompute(&self) -> GraphResult<FullRecomputeCheck>
where
O: PartialEq,
{
self.full_recompute_check()
}
pub fn assert_incremental_equals_full(&self) -> GraphResult<FullRecomputeCheck>
where
O: PartialEq,
{
self.full_recompute_check()
}
pub fn full_recompute_check(&self) -> GraphResult<FullRecomputeCheck>
where
O: PartialEq,
{
let mut full = self.clone();
full.derived_values.clear();
full.collection_values.clear();
full.previous_collection_values.clear();
full.collection_diffs.clear();
full.resource_owners.clear();
full.output_values.clear();
let order = full.derived_topological_order()?;
for node in &order {
let dependencies = full
.nodes
.get(node)
.expect("derived node metadata exists")
.dependencies()
.clone();
let value = full.compute_derived(*node, dependencies.as_slice())?;
full.derived_values.insert(*node, value);
}
for node in &order {
let incremental = self
.derived_values
.get(node)
.ok_or(GraphError::FullRecomputeMismatch(*node))?;
let recomputed = full
.derived_values
.get(node)
.ok_or(GraphError::FullRecomputeMismatch(*node))?;
if !incremental.equals(recomputed.as_ref()) {
return Err(GraphError::FullRecomputeMismatch(*node));
}
}
let collection_order = full.collection_topological_order()?;
let all_nodes: Vec<NodeId> = full.nodes.keys().copied().collect();
full.recompute_dirty_collections(&all_nodes)?;
self.compare_full_recomputed_collections(&full, &collection_order)?;
let checked_resources = self.compare_full_recomputed_resources(&mut full)?;
let checked_outputs = self.compare_full_recomputed_outputs(&mut full, &all_nodes)?;
Ok(FullRecomputeCheck {
checked_derived: order,
checked_collections: collection_order,
checked_resources,
checked_outputs,
})
}
fn compare_full_recomputed_resources(
&self,
full: &mut Graph<C, O>,
) -> GraphResult<Vec<ResourceKey>> {
let planner_collections: Vec<NodeId> = full
.resource_planners
.iter()
.map(|planner| planner.collection)
.collect();
full.baseline_collection_diffs(&planner_collections);
full.produce_resource_plan(&[])?;
if self.resource_owners != full.resource_owners {
let node = planner_collections
.into_iter()
.next()
.unwrap_or_else(|| NodeId::from_index(1));
return Err(GraphError::FullRecomputeMismatch(node));
}
Ok(self.resource_owners.keys().cloned().collect())
}
fn compare_full_recomputed_outputs(
&self,
full: &mut Graph<C, O>,
all_nodes: &[NodeId],
) -> GraphResult<Vec<OutputKey>>
where
O: PartialEq,
{
full.produce_output_frames(
all_nodes,
&[],
&BTreeMap::new(),
self.next_transaction_id,
self.revision,
)?;
if self.output_values != full.output_values {
let node = self
.outputs
.values()
.flat_map(|meta| meta.dependencies().as_slice().iter().copied())
.next()
.unwrap_or_else(|| NodeId::from_index(1));
return Err(GraphError::FullRecomputeMismatch(node));
}
Ok(self.output_values.keys().copied().collect())
}
}