cuenv_task_graph/lib.rs
1//! Task graph DAG algorithms and dependency resolution for cuenv.
2//!
3//! This crate provides a directed acyclic graph (DAG) implementation for
4//! task dependency resolution and execution ordering using petgraph.
5//!
6//! # Key Types
7//!
8//! - [`TaskGraph`]: The main graph structure for building and querying task dependencies
9//! - [`TaskNodeData`]: Trait that task types must implement to be stored in the graph
10//! - [`GraphNode`]: A node in the graph containing the task name and data
11//!
12//! # Example
13//!
14//! ```ignore
15//! use cuenv_task_graph::{TaskGraph, TaskNodeData};
16//!
17//! // Define a simple task type
18//! struct MyTask {
19//! depends_on: Vec<String>,
20//! }
21//!
22//! impl TaskNodeData for MyTask {
23//! fn depends_on(&self) -> &[String] {
24//! &self.depends_on
25//! }
26//! }
27//!
28//! // Build a graph
29//! let mut graph = TaskGraph::new();
30//! graph.add_task("build", MyTask { depends_on: vec![] })?;
31//! graph.add_task("test", MyTask { depends_on: vec!["build".to_string()] })?;
32//! graph.add_dependency_edges()?;
33//!
34//! // Get execution order
35//! let sorted = graph.topological_sort()?;
36//! ```
37
38mod error;
39mod graph;
40mod resolver;
41mod traversal;
42mod validation;
43
44pub use error::{Error, Result};
45pub use graph::{GraphNode, TaskGraph, compute_transitive_closure};
46pub use resolver::{TaskResolution, TaskResolver};
47pub use traversal::{ParallelGroups, TopologicalOrder};
48pub use validation::ValidationResult;
49
50/// Trait for task data that can be stored in the task graph.
51///
52/// Implement this trait for your task type to enable it to be stored
53/// in a [`TaskGraph`] and participate in dependency resolution.
54pub trait TaskNodeData: Clone {
55 /// Returns an iterator over the names of tasks this task depends on.
56 fn dependency_names(&self) -> impl Iterator<Item = &str>;
57
58 /// Adds a dependency to this task by name.
59 ///
60 /// Default implementation panics. Override this method if mutation is needed
61 /// (e.g., for applying group-level dependencies to subtasks).
62 ///
63 /// # Panics
64 ///
65 /// Panics if not overridden - implement for task types that need mutable dependency addition.
66 #[allow(clippy::unimplemented)]
67 fn add_dependency(&mut self, _dep: String) {
68 unreachable!("add_dependency not supported for this task type - override in impl")
69 }
70
71 /// Returns true if this task has a dependency on the given task name.
72 fn has_dependency(&self, name: &str) -> bool {
73 self.dependency_names().any(|n| n == name)
74 }
75}