TaskData#

One task, summary or milestone. Tasks go in ProjectData::tasks; the same struct adds a task to a live project through SchedulingChanges::tasks.add. Build it with TaskData::new and struct update syntax, since TaskData doesn't implement Default.

Declaration#

#[derive(Clone, Debug)]
pub struct TaskData {
    pub id: Id,
    pub parent: Option<Id>,
    pub task_type: TaskType,
    pub start_date: Option<DateTime>,
    pub end_date: Option<DateTime>,
    pub duration: Option<f64>,
    pub duration_unit: Option<TimeUnit>,
    pub constraint_type: Option<ConstraintType>,
    pub constraint_date: Option<DateTime>,
    pub auto_scheduling: bool,
    pub unscheduled: bool,
    pub progress: f64,
    pub priority: u16,
    pub leveling_delay: f64,
    pub pauses: Vec<Pause>,
    pub calendar_id: Option<Id>,
}

Constructors#

new#

pub fn new(id: impl Into<Id>) -> TaskData

Creates a task with the given id and every other field at the default listed under Fields. Accepts anything that converts into an Id: 1, "design", a String.

Returns a plain task (TaskType::Task) with no dates, no duration and automatic scheduling on.

Fields#

id#

pub id: Id

Task id, unique among the project's tasks.

parent#

pub parent: Option<Id>

Id of the parent task. None, "" or a value equal to SchedulingConfig::root_id means a top-level task.

Default: None.

task_type#

pub task_type: TaskType

Plain task, summary or milestone. Decides which date fields are needed, see Dates by task type.

Default: TaskType::Task.

start_date#

pub start_date: Option<DateTime>

Start of the task.

Default: None.

end_date#

pub end_date: Option<DateTime>

End of the task. Must not be before start_date.

Default: None.

duration#

pub duration: Option<f64>

Working time in duration_unit. Finite and >= 0.

Default: None.

duration_unit#

pub duration_unit: Option<TimeUnit>

Unit of duration, leveling_delay and pauses. None uses SchedulingConfig::duration_unit.

Default: None.

constraint_type#

pub constraint_type: Option<ConstraintType>

Date constraint on the task. Takes effect only when SchedulingConfig::apply_constraints is true.

Default: None.

constraint_date#

pub constraint_date: Option<DateTime>

Date of the constraint. Required when constraint_type is a dated type (every type except Asap and Alap).

Default: None.

auto_scheduling#

pub auto_scheduling: bool

false fixes the task: the scheduler never moves it.

Default: true.

unscheduled#

pub unscheduled: bool

true leaves the task and all its descendants out of scheduling and out of results. Such tasks need no dates.

Default: false.

progress#

pub progress: f64

Completed share, from 0.0 to 1.0. With SchedulingConfig::use_progress, 1.0 marks the task completed and fixed.

Default: 0.0.

priority#

pub priority: u16

Leveling priority, from 0 to 1000. When leveling picks which task to delay, the lower priority gives way; 1000 is never leveled.

Default: 500.

leveling_delay#

pub leveling_delay: f64

Elapsed time added before the task's driven start, in duration_unit (a day is 24 hours). Finite and >= 0. Written by Project::level.

Default: 0.0.

pauses#

pub pauses: Vec<Pause>

Splits in the task's work, sorted by at and non-overlapping. Written by Project::level. Ignored on summaries, milestones and unscheduled tasks.

Default: empty.

calendar_id#

pub calendar_id: Option<Id>

Id of the task's working calendar. None uses the "global" calendar, or the nearest ancestor's calendar under CalendarMode::TaskInherited.

Default: None.

Dates by task type#

start_date, end_date and duration are read differently for each TaskType. Unscheduled tasks skip these rules.

Task type Accepted input Result
Task start_date + duration End computed forward on the task's calendar, around any pauses.
Task end_date + duration Start computed backward from the end.
Task start_date + end_date duration is the working time between the dates.
Task all three Accepted only when start_date + duration lands on end_date.
Summary start_date + end_date The given span. duration is ignored.
Summary neither date Span taken from the dated children.
Milestone start_date or end_date A zero-length task at that date. duration is ignored.

A summary with only one of the two dates is an error, and so is a plain task with fewer than two of the three fields.

Errors#

Under the default Validation::Strict, an invalid task fails Project::solve, schedule and Project::analyze with Error::Input at a path under tasks[i]:

Path When it occurs
tasks[i].progress progress isn't finite or is outside 0.0..=1.0
tasks[i].priority priority is greater than 1000
tasks[i].leveling_delay leveling_delay isn't finite or is negative
tasks[i].duration duration isn't finite or is negative; or all three date fields are set and disagree
tasks[i].constraint_date a dated constraint_type has no constraint_date
tasks[i].pauses[j] pause j breaks a Pause rule
tasks[i].calendar_id calendar_id names no calendar in ProjectData::calendars and isn't "global"
tasks[i].start_date a plain task has fewer than two of start_date, end_date, duration; a summary has only one date; a milestone has no date
tasks[i].end_date end_date is before start_date
tasks[i] a summary has no dates and no dated children

Rules across tasks (unique ids, known parent, no hierarchy cycle) are on ProjectData. Validation::Repair fixes several of these cases instead of rejecting them.

Example#

A summary with two dated children, a milestone at the end, and a task with a "start no earlier than" constraint:

use plen_core::{
    schedule, ConstraintType, DateTime, ProjectData, SchedulingConfig, SolveOptions, TaskData,
    TaskType,
};

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

    let data = ProjectData {
        config: SchedulingConfig {
            apply_constraints: true,
            ..Default::default()
        },
        tasks: vec![
            TaskData {
                task_type: TaskType::Summary,
                ..TaskData::new("phase")
            },
            TaskData {
                parent: Some("phase".into()),
                start_date: Some(monday),
                duration: Some(2.0),
                ..TaskData::new("design")
            },
            TaskData {
                parent: Some("phase".into()),
                start_date: Some(monday),
                duration: Some(3.0),
                constraint_type: Some(ConstraintType::Snet),
                constraint_date: Some(friday),
                ..TaskData::new("build")
            },
            TaskData {
                task_type: TaskType::Milestone,
                start_date: Some(friday),
                ..TaskData::new("release")
            },
        ],
        ..Default::default()
    };

    let result = schedule(data, &SolveOptions::default())?;
    for update in &result.updates {
        println!("{update:?}");
    }
    Ok(())
}

For how links, constraints and summaries move tasks, see Links, constraints and summaries.