Skip to main content

TaskGraph

Struct TaskGraph 

Source
pub struct TaskGraph<T: TaskNodeData> { /* private fields */ }
Expand description

Task graph for dependency resolution and execution ordering.

This is a generic graph that can hold any task type implementing TaskNodeData. It provides methods for building the graph, resolving dependencies, and computing execution order.

Implementations§

Source§

impl<T: TaskNodeData> TaskGraph<T>

Source

pub fn new() -> Self

Create a new empty task graph.

Source

pub fn add_task(&mut self, name: &str, task: T) -> Result<NodeIndex>

Add a single task to the graph.

If a task with the same name already exists, returns the existing node index.

§Errors

Currently infallible, but returns Result for API consistency.

Source

pub fn get_node_mut(&mut self, index: NodeIndex) -> Option<&mut GraphNode<T>>

Get a mutable reference to a task node by index.

Source

pub fn get_node_by_name(&self, name: &str) -> Option<&GraphNode<T>>

Get a reference to a task node by name.

Source

pub fn register_group(&mut self, prefix: &str, children: Vec<String>)

Register a group of child task names under a group prefix.

This enables group-level dependency expansion where depending on a group name will expand to depend on all child tasks.

Source

pub fn add_dependency_edges(&mut self) -> Result<()>

Add dependency edges after all tasks have been added.

This ensures proper cycle detection and missing dependency validation.

§Errors

Returns an error if any task depends on a non-existent task.

Source

pub fn add_edge(&mut self, from: NodeIndex, to: NodeIndex)

Add a direct edge between two tasks.

This is a low-level method for adding edges directly, typically used for sequential group ordering.

Source

pub fn has_cycles(&self) -> bool

Check if the graph has cycles.

Source

pub fn topological_sort(&self) -> Result<Vec<GraphNode<T>>>

Get topologically sorted list of tasks.

§Errors

Returns an error if the graph contains cycles.

Source

pub fn get_parallel_groups(&self) -> Result<Vec<Vec<GraphNode<T>>>>

Get all tasks that can run in parallel (no dependencies between them).

Returns a vector of parallel groups, where each group contains tasks that can execute concurrently. Groups are ordered by dependency level.

§Errors

Returns an error if the graph contains cycles.

Source

pub fn task_count(&self) -> usize

Get the number of tasks in the graph.

Source

pub fn contains_task(&self, name: &str) -> bool

Check if a task exists in the graph.

Source

pub fn get_node_index(&self, name: &str) -> Option<NodeIndex>

Get the node index for a task by name.

Source

pub fn iter_nodes(&self) -> impl Iterator<Item = (NodeIndex, &GraphNode<T>)>

Iterate over all nodes in the graph.

Source

pub fn build_for_task<F>(&mut self, task_name: &str, get_task: F) -> Result<()>
where F: FnMut(&str) -> Option<T>,

Build graph for a specific task and all its transitive dependencies.

This method takes an iterator of all available tasks and builds only the subgraph needed for the requested task.

§Arguments
  • task_name - The name of the task to build the graph for
  • get_task - Function that returns the task data for a given name
§Errors

Returns an error if dependencies cannot be resolved.

Source

pub fn build_for_task_with_resolver<R>( &mut self, task_name: &str, resolver: &R, ) -> Result<()>
where R: TaskResolver<T>,

Build graph for a specific task using a resolver that handles group expansion.

This method uses the TaskResolver trait to resolve task names, which enables unified handling of single tasks and groups (sequential/parallel).

§Arguments
  • task_name - The name of the task to build the graph for
  • resolver - Implementation of TaskResolver that provides task lookup and group expansion
§Errors

Returns an error if dependencies cannot be resolved.

Source

pub fn compute_affected<F, E>( &self, pipeline_tasks: &[impl AsRef<str>], is_directly_affected: F, is_external_affected: Option<E>, ) -> Vec<String>
where F: Fn(&T) -> bool, E: Fn(&str) -> bool,

Compute which tasks from a pipeline are affected, using transitive dependency propagation.

This method determines which tasks need to run based on:

  1. Direct effect: The predicate returns true for the task
  2. Transitive effect: A task depends on an affected task
  3. External effect: An external dependency (e.g., #project:task) is affected
§Arguments
  • pipeline_tasks - The names of tasks in the pipeline to check
  • is_directly_affected - Predicate that returns true if a task is directly affected
  • is_external_affected - Optional predicate for external dependencies (starting with #)
§Returns

A vector of task names that are affected, in pipeline order.

§Example
// Without external dependency checking
let affected = graph.compute_affected(
    &["build", "test", "deploy"],
    |task| task.is_affected_by(&changed_files, &project_root),
    None::<fn(&str) -> bool>,
);

// With external dependency checking (for CI cross-project deps)
let affected = graph.compute_affected(
    &["build", "test", "deploy"],
    |task| task.is_affected_by(&changed_files, &project_root),
    Some(|dep: &str| check_external_dependency(dep, &all_projects, &changed_files)),
);
Source§

impl<T: TaskNodeData> TaskGraph<T>

Source

pub fn validate(&self) -> ValidationResult

Validate the graph structure.

Checks for:

  • Cycles in the dependency graph

Note: Missing dependencies are caught during add_dependency_edges(), so this method primarily checks for cycles after edges are added.

Trait Implementations§

Source§

impl<T: TaskNodeData> Default for TaskGraph<T>

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl<T> Freeze for TaskGraph<T>

§

impl<T> RefUnwindSafe for TaskGraph<T>
where T: RefUnwindSafe,

§

impl<T> Send for TaskGraph<T>
where T: Send,

§

impl<T> Sync for TaskGraph<T>
where T: Sync,

§

impl<T> Unpin for TaskGraph<T>
where T: Unpin,

§

impl<T> UnsafeUnpin for TaskGraph<T>

§

impl<T> UnwindSafe for TaskGraph<T>
where T: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more