1use std::any::TypeId;
6use std::collections::{HashMap, VecDeque};
7
8pub struct ModuleEntry {
10 pub type_id: TypeId,
12 pub name: &'static str,
14 pub dependencies: Vec<(&'static str, TypeId)>,
16}
17
18pub struct DependencyGraph {
20 entries: Vec<ModuleEntry>,
21 index: HashMap<TypeId, usize>,
22}
23
24impl DependencyGraph {
25 #[must_use]
27 pub fn new() -> Self {
28 DependencyGraph {
29 entries: Vec::new(),
30 index: HashMap::new(),
31 }
32 }
33
34 pub fn add(&mut self, entry: ModuleEntry) -> Result<(), &'static str> {
40 if self.index.contains_key(&entry.type_id) {
41 return Err(entry.name);
42 }
43 let idx = self.entries.len();
44 self.index.insert(entry.type_id, idx);
45 self.entries.push(entry);
46 Ok(())
47 }
48
49 pub fn validate(&self) -> Result<Vec<TypeId>, GraphError> {
57 for entry in &self.entries {
59 for (dep_name, dep_id) in &entry.dependencies {
60 if !self.index.contains_key(dep_id) {
61 return Err(GraphError::DependencyMissing {
62 module: entry.name,
63 missing: dep_name,
64 });
65 }
66 }
67 }
68
69 let n = self.entries.len();
71 let mut in_degree = vec![0usize; n];
72 let mut adj: Vec<Vec<usize>> = vec![Vec::new(); n];
73
74 for (i, entry) in self.entries.iter().enumerate() {
75 for (_dep_name, dep_id) in &entry.dependencies {
76 if let Some(&dep_idx) = self.index.get(dep_id) {
77 adj[dep_idx].push(i);
78 in_degree[i] += 1;
79 }
80 }
81 }
82
83 let mut queue: VecDeque<usize> = VecDeque::new();
84 for (i, deg) in in_degree.iter().enumerate().take(n) {
85 if *deg == 0 {
86 queue.push_back(i);
87 }
88 }
89
90 let mut sorted = Vec::with_capacity(n);
91 while let Some(node) = queue.pop_front() {
92 sorted.push(self.entries[node].type_id);
93 for &neighbor in &adj[node] {
94 in_degree[neighbor] -= 1;
95 if in_degree[neighbor] == 0 {
96 queue.push_back(neighbor);
97 }
98 }
99 }
100
101 if sorted.len() != n {
102 let cycle = self.find_cycle();
104 return Err(GraphError::CycleDetected { cycle });
105 }
106
107 Ok(sorted)
108 }
109
110 fn find_cycle(&self) -> Vec<&'static str> {
112 fn dfs(
113 node: usize,
114 entries: &[ModuleEntry],
115 index: &HashMap<TypeId, usize>,
116 visited: &mut [u8],
117 stack: &mut Vec<usize>,
118 cycle_names: &mut Vec<&'static str>,
119 ) -> bool {
120 visited[node] = 1;
121 stack.push(node);
122
123 for (_dep_name, dep_id) in &entries[node].dependencies {
124 if let Some(&dep_idx) = index.get(dep_id) {
125 if visited[dep_idx] == 1 {
126 let start = stack
128 .iter()
129 .position(|&x| x == dep_idx)
130 .expect("invariant: dep_idx must be in stack (visited[dep_idx] == 1)");
131 for &idx in &stack[start..] {
132 cycle_names.push(entries[idx].name);
133 }
134 cycle_names.push(entries[dep_idx].name);
135 return true;
136 }
137 if visited[dep_idx] == 0
138 && dfs(dep_idx, entries, index, visited, stack, cycle_names)
139 {
140 return true;
141 }
142 }
143 }
144
145 stack.pop();
146 visited[node] = 2;
147 false
148 }
149
150 let n = self.entries.len();
151 let mut visited = vec![0u8; n]; let mut stack = Vec::new();
153 let mut cycle_names = Vec::new();
154
155 for i in 0..n {
156 if visited[i] == 0
157 && dfs(
158 i,
159 &self.entries,
160 &self.index,
161 &mut visited,
162 &mut stack,
163 &mut cycle_names,
164 )
165 {
166 return cycle_names;
167 }
168 }
169
170 vec!["<unknown cycle>"]
171 }
172
173 #[must_use]
175 pub fn dependency_names(&self, type_id: TypeId) -> Vec<&'static str> {
176 if let Some(&idx) = self.index.get(&type_id) {
177 self.entries[idx]
178 .dependencies
179 .iter()
180 .map(|(name, _)| *name)
181 .collect()
182 } else {
183 Vec::new()
184 }
185 }
186
187 #[must_use]
189 pub fn entries(&self) -> &[ModuleEntry] {
190 &self.entries
191 }
192
193 #[must_use]
195 pub fn name_of(&self, type_id: TypeId) -> Option<&'static str> {
196 self.index.get(&type_id).map(|&idx| self.entries[idx].name)
197 }
198}
199
200impl Default for DependencyGraph {
201 fn default() -> Self {
202 Self::new()
203 }
204}
205
206#[derive(Debug)]
208pub enum GraphError {
209 DependencyMissing {
211 module: &'static str,
212 missing: &'static str,
213 },
214 CycleDetected { cycle: Vec<&'static str> },
216}