Cycle#

One simple directed dependency cycle in the project. You don't build it yourself. Read it from ScheduleResult::cycles, which holds one Cycle per unique cycle. A cycle is data in the result, not an error. For what a cyclic run does to dates and updates, see ScheduleResult.

Declaration#

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Cycle {
    pub tasks: Vec<Id>,
    pub links: Vec<Id>,
}

With the serde feature, it also implements Serialize and Deserialize.

Fields#

Name Type Description
tasks Vec<Id> Ids of the tasks on the cycle, in the order the cycle passes through them.
links Vec<Id> Ids of the links that form the cycle, in path order. Each link id appears once. A cycle closed through summary containment rather than a link has fewer links than tasks.

Each rotation of a cycle is reported once. Two cycles over the same tasks through different parallel links are separate entries. Fixed and completed tasks are included.

Serialization#

With the serde feature, a Cycle serializes as:

{ "tasks": ["a", "b"], "links": ["ab", "ba"] }

Example#

Link two tasks in both directions and print the cycle.

use plen_core::{schedule, DateTime, LinkData, LinkType, ProjectData, SolveOptions, TaskData};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let monday = DateTime::from_ymd_hm(2026, 1, 5, 8, 0).ok_or("invalid date")?;

    let mut a = TaskData::new("a");
    a.start_date = Some(monday);
    a.duration = Some(1.0);

    let mut b = TaskData::new("b");
    b.start_date = Some(monday);
    b.duration = Some(1.0);

    let link = |id: &str, source: &str, target: &str| LinkData {
        id: id.into(),
        source: source.into(),
        target: target.into(),
        link_type: LinkType::Fs,
        lag: 0.0,
        lag_unit: None,
    };

    let data = ProjectData {
        tasks: vec![a, b],
        links: vec![link("ab", "a", "b"), link("ba", "b", "a")],
        ..Default::default()
    };

    let result = schedule(data, &SolveOptions::default())?;

    for cycle in &result.cycles {
        let tasks: Vec<String> = cycle.tasks.iter().map(|id| id.to_string()).collect();
        let links: Vec<String> = cycle.links.iter().map(|id| id.to_string()).collect();
        println!("tasks: {}; links: {}", tasks.join(" -> "), links.join(", "));
        // tasks: a -> b; links: ab, ba
    }
    Ok(())
}