MCPcopy Create free account
hub / github.com/NodeDB-Lab/nodedb / topo_sort

Function topo_sort

nodedb-cluster/src/subsystem/topo_sort.rs:26–90  ·  view source on GitHub ↗

Topo-sort `subsystems` by their declared dependencies. Returns a `Vec ` where each element is an index into `subsystems` and the order represents a valid start sequence (dependencies before dependents). # Errors - `TopoError::UnknownDependency` — a subsystem lists a dependency name that is not present in `subsystems`. - `TopoError::Cycle` — a circular dependency was detected.

(subsystems: &[Arc<dyn ClusterSubsystem>])

Source from the content-addressed store, hash-verified

24/// that is not present in `subsystems`.
25/// - `TopoError::Cycle` — a circular dependency was detected.
26pub fn topo_sort(subsystems: &[Arc<dyn ClusterSubsystem>]) -> Result<Vec<usize>, TopoError> {
27 // Build name → index map.
28 let name_to_idx: HashMap<&'static str, usize> = subsystems
29 .iter()
30 .enumerate()
31 .map(|(i, s)| (s.name(), i))
32 .collect();
33
34 // Validate all dependency names and build adjacency (dep → dependent)
35 // plus in-degree per node.
36 let n = subsystems.len();
37 let mut in_degree = vec![0usize; n];
38 // adjacency[i] = list of indices that depend on i (i must start before them)
39 let mut adjacency: Vec<Vec<usize>> = vec![Vec::new(); n];
40
41 for (i, subsystem) in subsystems.iter().enumerate() {
42 for &dep_name in subsystem.dependencies() {
43 let dep_idx =
44 name_to_idx
45 .get(dep_name)
46 .copied()
47 .ok_or(TopoError::UnknownDependency {
48 subsystem: subsystem.name(),
49 dependency: dep_name,
50 })?;
51 // dep_idx must come before i
52 adjacency[dep_idx].push(i);
53 in_degree[i] += 1;
54 }
55 }
56
57 // Kahn's algorithm.
58 let mut queue: VecDeque<usize> = (0..n).filter(|&i| in_degree[i] == 0).collect();
59
60 let mut order = Vec::with_capacity(n);
61
62 while let Some(idx) = queue.pop_front() {
63 order.push(idx);
64 for &dependent in &adjacency[idx] {
65 in_degree[dependent] -= 1;
66 if in_degree[dependent] == 0 {
67 queue.push_back(dependent);
68 }
69 }
70 }
71
72 if order.len() != n {
73 // Some nodes still have non-zero in-degree — there is a cycle.
74 // Collect the names of nodes still in the cycle for diagnostics.
75 let cycle_names: Vec<&'static str> = in_degree
76 .iter()
77 .enumerate()
78 .filter_map(|(i, &deg)| {
79 if deg > 0 {
80 Some(subsystems[i].name())
81 } else {
82 None
83 }

Callers 11

empty_listFunction · 0.85
single_no_depsFunction · 0.85
linear_chainFunction · 0.85
two_independent_rootsFunction · 0.85
diamond_dependencyFunction · 0.85
cycle_detectedFunction · 0.85
missing_dependencyFunction · 0.85
start_allMethod · 0.85

Calls 8

collectMethod · 0.80
pop_frontMethod · 0.80
iterMethod · 0.45
nameMethod · 0.45
lenMethod · 0.45
dependenciesMethod · 0.45
getMethod · 0.45
pushMethod · 0.45

Tested by 9

empty_listFunction · 0.68
single_no_depsFunction · 0.68
linear_chainFunction · 0.68
two_independent_rootsFunction · 0.68
diamond_dependencyFunction · 0.68
cycle_detectedFunction · 0.68
missing_dependencyFunction · 0.68