1use std::collections::{HashMap, HashSet, VecDeque};
6
7use dashmap::DashMap;
8
9use crate::error::{Error, Result};
10
11#[derive(Debug, Clone)]
13pub struct ModuleDependency {
14 pub name: String,
16 pub min_version: Option<String>,
18 pub optional: bool,
20}
21
22#[derive(Debug, Clone)]
24pub struct DependencyNode {
25 pub name: String,
27 pub dependencies: Vec<ModuleDependency>,
29 pub dependents: HashSet<String>,
31 pub loaded: bool,
33}
34
35#[derive(Debug)]
37pub struct DependencyGraph {
38 nodes: DashMap<String, DependencyNode>,
40}
41
42impl DependencyGraph {
43 pub fn new() -> Self {
45 Self {
46 nodes: DashMap::new(),
47 }
48 }
49
50 pub fn add_module(&self, name: &str, dependencies: Vec<ModuleDependency>) {
52 let node = DependencyNode {
53 name: name.to_string(),
54 dependencies,
55 dependents: HashSet::new(),
56 loaded: false,
57 };
58 self.nodes.insert(name.to_string(), node);
59 }
60
61 pub fn mark_loaded(&self, name: &str) {
63 if let Some(mut node) = self.nodes.get_mut(name) {
64 node.loaded = true;
65 }
66 }
67
68 pub fn mark_unloaded(&self, name: &str) {
70 if let Some(mut node) = self.nodes.get_mut(name) {
71 node.loaded = false;
72 }
73 }
74
75 pub fn dependencies_satisfied(&self, name: &str) -> bool {
77 let node = match self.nodes.get(name) {
78 Some(n) => n,
79 None => return false,
80 };
81
82 for dep in &node.dependencies {
83 if dep.optional {
84 continue;
85 }
86
87 let dep_node = match self.nodes.get(&dep.name) {
88 Some(n) => n,
89 None => return false, };
91
92 if !dep_node.loaded {
93 return false; }
95 }
96
97 true
98 }
99
100 pub fn load_order(&self) -> Result<Vec<String>> {
104 let mut in_degree: HashMap<String, usize> = HashMap::new();
106 let mut queue: VecDeque<String> = VecDeque::new();
107 let mut result: Vec<String> = Vec::new();
108
109 for entry in self.nodes.iter() {
111 let name = entry.key().clone();
112 let node = entry.value();
113 let required_deps = node.dependencies.iter().filter(|d| !d.optional).count();
114 in_degree.insert(name.clone(), required_deps);
115
116 if required_deps == 0 {
117 queue.push_back(name.clone());
118 }
119 }
120
121 while let Some(name) = queue.pop_front() {
123 result.push(name.clone());
124
125 for entry in self.nodes.iter() {
127 let node = entry.value();
128 if node.dependencies.iter().any(|d| d.name == name && !d.optional) {
129 let in_deg = in_degree.get_mut(entry.key()).unwrap();
130 *in_deg -= 1;
131 if *in_deg == 0 {
132 queue.push_back(entry.key().clone());
133 }
134 }
135 }
136 }
137
138 if result.len() != self.nodes.len() {
140 return Err(Error::ModuleCallFailed(-1)); }
142
143 Ok(result)
144 }
145
146 pub fn unload_order(&self) -> Result<Vec<String>> {
148 let mut order = self.load_order()?;
149 order.reverse();
150 Ok(order)
151 }
152
153 pub fn has_cycle(&self) -> bool {
155 self.load_order().is_err()
156 }
157
158 pub fn all_dependencies(&self, name: &str) -> HashSet<String> {
160 let mut result = HashSet::new();
161 let mut queue: VecDeque<String> = VecDeque::new();
162
163 if let Some(node) = self.nodes.get(name) {
164 for dep in &node.dependencies {
165 queue.push_back(dep.name.clone());
166 }
167 }
168
169 while let Some(dep_name) = queue.pop_front() {
170 if result.contains(&dep_name) {
171 continue;
172 }
173 result.insert(dep_name.clone());
174
175 if let Some(dep_node) = self.nodes.get(&dep_name) {
176 for sub_dep in &dep_node.dependencies {
177 queue.push_back(sub_dep.name.clone());
178 }
179 }
180 }
181
182 result
183 }
184
185 pub fn all_dependents(&self, name: &str) -> HashSet<String> {
187 let mut result = HashSet::new();
188 let mut queue: VecDeque<String> = VecDeque::new();
189
190 for entry in self.nodes.iter() {
192 let node = entry.value();
193 if node.dependencies.iter().any(|d| d.name == name) {
194 queue.push_back(entry.key().clone());
195 }
196 }
197
198 while let Some(dep_name) = queue.pop_front() {
199 if result.contains(&dep_name) {
200 continue;
201 }
202 result.insert(dep_name.clone());
203
204 for entry in self.nodes.iter() {
206 let node = entry.value();
207 if node.dependencies.iter().any(|d| d.name == dep_name) {
208 queue.push_back(entry.key().clone());
209 }
210 }
211 }
212
213 result
214 }
215
216 pub fn can_unload(&self, name: &str) -> bool {
218 let dependents = self.all_dependents(name);
219
220 for dep_name in &dependents {
221 if let Some(node) = self.nodes.get(dep_name) {
222 if node.loaded {
223 return false; }
225 }
226 }
227
228 true
229 }
230
231 pub fn module_count(&self) -> usize {
233 self.nodes.len()
234 }
235
236 pub fn all_modules(&self) -> Vec<String> {
238 self.nodes.iter().map(|e| e.key().clone()).collect()
239 }
240
241 pub fn get_module(&self, name: &str) -> Option<DependencyNode> {
243 self.nodes.get(name).map(|e| e.value().clone())
244 }
245}
246
247impl Default for DependencyGraph {
248 fn default() -> Self {
249 Self::new()
250 }
251}
252
253#[derive(Debug, Clone)]
255pub struct CallContext {
256 pub caller: Option<String>,
258 pub target: String,
260 pub depth: usize,
262 pub max_depth: usize,
264 pub trace_id: Option<u128>,
266}
267
268impl CallContext {
269 pub fn new(target: String) -> Self {
271 Self {
272 caller: None,
273 target,
274 depth: 0,
275 max_depth: 10,
276 trace_id: None,
277 }
278 }
279
280 pub fn child(&self, target: String) -> Option<Self> {
282 if self.depth >= self.max_depth {
283 return None; }
285
286 Some(Self {
287 caller: Some(self.target.clone()),
288 target,
289 depth: self.depth + 1,
290 max_depth: self.max_depth,
291 trace_id: self.trace_id,
292 })
293 }
294
295 pub fn is_root(&self) -> bool {
297 self.caller.is_none()
298 }
299
300 pub fn is_nested(&self) -> bool {
302 self.caller.is_some()
303 }
304}
305
306#[cfg(test)]
307mod tests {
308 use super::*;
309
310 #[test]
311 fn test_dependency_graph_basic() {
312 let graph = DependencyGraph::new();
313
314 graph.add_module("A", vec![]);
315 graph.add_module("B", vec![
316 ModuleDependency { name: "A".to_string(), min_version: None, optional: false }
317 ]);
318 graph.add_module("C", vec![
319 ModuleDependency { name: "B".to_string(), min_version: None, optional: false }
320 ]);
321
322 let order = graph.load_order().unwrap();
324 assert_eq!(order, vec!["A", "B", "C"]);
325
326 let order = graph.unload_order().unwrap();
328 assert_eq!(order, vec!["C", "B", "A"]);
329 }
330
331 #[test]
332 fn test_dependency_graph_optional() {
333 let graph = DependencyGraph::new();
334
335 graph.add_module("A", vec![]);
336 graph.add_module("B", vec![
337 ModuleDependency { name: "A".to_string(), min_version: None, optional: true }
338 ]);
339
340 graph.mark_loaded("B");
342 assert!(graph.dependencies_satisfied("B"));
343 }
344
345 #[test]
346 fn test_dependency_graph_cycle_detection() {
347 let graph = DependencyGraph::new();
348
349 graph.add_module("A", vec![
350 ModuleDependency { name: "B".to_string(), min_version: None, optional: false }
351 ]);
352 graph.add_module("B", vec![
353 ModuleDependency { name: "A".to_string(), min_version: None, optional: false }
354 ]);
355
356 assert!(graph.has_cycle());
358 assert!(graph.load_order().is_err());
359 }
360
361 #[test]
362 fn test_call_context_depth() {
363 let root = CallContext::new("A".to_string());
364 assert_eq!(root.depth, 0);
365 assert!(root.is_root());
366
367 let child1 = root.child("B".to_string()).unwrap();
368 assert_eq!(child1.depth, 1);
369 assert!(child1.is_nested());
370
371 let child2 = child1.child("C".to_string()).unwrap();
372 assert_eq!(child2.depth, 2);
373
374 let mut ctx = root;
376 for i in 0..10 {
377 if let Some(next) = ctx.child(format!("M{}", i)) {
378 ctx = next;
379 }
380 }
381 assert!(ctx.child("M10".to_string()).is_none());
383 }
384
385 #[test]
386 fn test_transitive_dependencies() {
387 let graph = DependencyGraph::new();
388
389 graph.add_module("A", vec![]);
390 graph.add_module("B", vec![
391 ModuleDependency { name: "A".to_string(), min_version: None, optional: false }
392 ]);
393 graph.add_module("C", vec![
394 ModuleDependency { name: "B".to_string(), min_version: None, optional: false }
395 ]);
396
397 let deps = graph.all_dependencies("C");
399 assert!(deps.contains("A"));
400 assert!(deps.contains("B"));
401 assert_eq!(deps.len(), 2);
402 }
403
404 #[test]
405 fn test_can_unload() {
406 let graph = DependencyGraph::new();
407
408 graph.add_module("A", vec![]);
409 graph.add_module("B", vec![
410 ModuleDependency { name: "A".to_string(), min_version: None, optional: false }
411 ]);
412
413 graph.mark_loaded("A");
414 graph.mark_loaded("B");
415
416 assert!(!graph.can_unload("A"));
418
419 assert!(graph.can_unload("B"));
421
422 graph.mark_unloaded("B");
424 assert!(graph.can_unload("A"));
425 }
426}