1use crate::{Graph, GraphError, GraphResult, NodeId, OutputKey, ResourceKey};
2use std::collections::BTreeMap;
3
4#[derive(Clone, Debug, Eq, PartialEq)]
6pub struct FullRecomputeCheck {
7 pub checked_derived: Vec<NodeId>,
9 pub checked_collections: Vec<NodeId>,
11 pub checked_resources: Vec<ResourceKey>,
13 pub checked_outputs: Vec<OutputKey>,
15}
16
17impl<C, O: Clone> Graph<C, O> {
18 pub fn full_recompute(&self) -> GraphResult<FullRecomputeCheck>
20 where
21 O: PartialEq,
22 {
23 self.full_recompute_check()
24 }
25
26 pub fn assert_incremental_equals_full(&self) -> GraphResult<FullRecomputeCheck>
28 where
29 O: PartialEq,
30 {
31 self.full_recompute_check()
32 }
33
34 pub fn full_recompute_check(&self) -> GraphResult<FullRecomputeCheck>
36 where
37 O: PartialEq,
38 {
39 let mut full = self.clone();
40 full.derived_values.clear();
41 full.collection_values.clear();
42 full.previous_collection_values.clear();
43 full.collection_diffs.clear();
44 full.resource_owners.clear();
45 full.output_values.clear();
46 let order = full.derived_topological_order()?;
47
48 for node in &order {
49 let dependencies = full
50 .nodes
51 .get(node)
52 .expect("derived node metadata exists")
53 .dependencies()
54 .clone();
55 let value = full.compute_derived(*node, dependencies.as_slice())?;
56 full.derived_values.insert(*node, value);
57 }
58
59 for node in &order {
60 let incremental = self
61 .derived_values
62 .get(node)
63 .ok_or(GraphError::FullRecomputeMismatch(*node))?;
64 let recomputed = full
65 .derived_values
66 .get(node)
67 .ok_or(GraphError::FullRecomputeMismatch(*node))?;
68 if !incremental.equals(recomputed.as_ref()) {
69 return Err(GraphError::FullRecomputeMismatch(*node));
70 }
71 }
72
73 let collection_order = full.collection_topological_order()?;
74 let all_nodes: Vec<NodeId> = full.nodes.keys().copied().collect();
75 full.recompute_dirty_collections(&all_nodes)?;
76 self.compare_full_recomputed_collections(&full, &collection_order)?;
77 let checked_resources = self.compare_full_recomputed_resources(&mut full)?;
78 let checked_outputs = self.compare_full_recomputed_outputs(&mut full, &all_nodes)?;
79
80 Ok(FullRecomputeCheck {
81 checked_derived: order,
82 checked_collections: collection_order,
83 checked_resources,
84 checked_outputs,
85 })
86 }
87
88 fn compare_full_recomputed_resources(
89 &self,
90 full: &mut Graph<C, O>,
91 ) -> GraphResult<Vec<ResourceKey>> {
92 let planner_collections: Vec<NodeId> = full
93 .resource_planners
94 .iter()
95 .map(|planner| planner.collection)
96 .collect();
97 full.baseline_collection_diffs(&planner_collections);
98 full.produce_resource_plan(&[])?;
99 if self.resource_owners != full.resource_owners {
100 let node = planner_collections
101 .into_iter()
102 .next()
103 .unwrap_or_else(|| NodeId::from_index(1));
104 return Err(GraphError::FullRecomputeMismatch(node));
105 }
106 Ok(self.resource_owners.keys().cloned().collect())
107 }
108
109 fn compare_full_recomputed_outputs(
110 &self,
111 full: &mut Graph<C, O>,
112 all_nodes: &[NodeId],
113 ) -> GraphResult<Vec<OutputKey>>
114 where
115 O: PartialEq,
116 {
117 full.produce_output_frames(
118 all_nodes,
119 &[],
120 &BTreeMap::new(),
121 self.next_transaction_id,
122 self.revision,
123 )?;
124 if self.output_values != full.output_values {
125 let node = self
126 .outputs
127 .values()
128 .flat_map(|meta| meta.dependencies().as_slice().iter().copied())
129 .next()
130 .unwrap_or_else(|| NodeId::from_index(1));
131 return Err(GraphError::FullRecomputeMismatch(node));
132 }
133 Ok(self.output_values.keys().copied().collect())
134 }
135}