1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
//! Shared analysis indexes built once per validate/plan/report pass.
use std::collections::{BTreeMap, BTreeSet};
use super::{known_data_flow_endpoints, DependencyGraph, PipelineContract, PipelineStep};
/// Precomputed indexes for graph analysis and validation hot paths.
///
/// Build once with [`AnalysisContext::build`] and reuse across validation phases,
/// planning, and report views to avoid repeated endpoint / step-id rebuilds.
#[derive(Debug, Clone)]
pub struct AnalysisContext<'a> {
/// Source contract.
pub contract: &'a PipelineContract,
/// Declared non-empty step identifiers.
pub step_ids: BTreeSet<&'a str>,
/// Steps keyed by identifier (includes empty ids if present).
pub steps_by_id: BTreeMap<&'a str, &'a PipelineStep>,
/// Declared data-flow endpoint paths.
pub known_endpoints: BTreeSet<String>,
/// Dependency graph derived from graph edges, control flow, and data flow.
pub graph: DependencyGraph,
}
impl<'a> AnalysisContext<'a> {
/// Build analysis indexes for `contract`.
pub fn build(contract: &'a PipelineContract) -> Self {
let step_ids = contract.step_ids();
let steps_by_id = contract
.steps
.iter()
.map(|step| (step.id.as_str(), step))
.collect();
let known_endpoints = known_data_flow_endpoints(contract);
let graph =
DependencyGraph::from_indexes(contract, &step_ids, &steps_by_id, &known_endpoints);
Self {
contract,
step_ids,
steps_by_id,
known_endpoints,
graph,
}
}
/// Returns whether `endpoint` refers to a declared interface or step port.
pub fn data_flow_endpoint_known(&self, endpoint: &str) -> bool {
super::endpoints::endpoint_known_with_indexes(
&self.known_endpoints,
&self.steps_by_id,
endpoint,
)
}
/// Returns a validated inter-step dependency from a data-flow declaration.
pub fn data_flow_step_dependency(&self, from: &str, to: &str) -> Option<(String, String)> {
super::endpoints::data_flow_step_dependency_with_indexes(
&self.step_ids,
&self.known_endpoints,
&self.steps_by_id,
from,
to,
)
}
}