ResourceData#

One resource that assignments book: a person, a team or a machine. It goes into ProjectData::resources on import, or into resources.add of SchedulingChanges for a live project. There's no constructor; build it with a struct literal. To change an existing resource, use ResourceUpdate.

Declaration#

#[derive(Clone, Debug)]
pub struct ResourceData {
    pub id: Id,
    pub capacity: Option<f64>,
    pub calendar_id: Option<Id>,
}

Fields#

id#

pub id: Id

Resource id. AssignmentData::resource refers to it. A numeric id must be finite.

capacity#

pub capacity: Option<f64>

Units of work the resource can carry at once, in assignment value units (1.0 = 100 %). 2.0 means two full-time assignments fit without overallocation. None takes SchedulingConfig::default_resource_capacity (1.0 by default).

Default: None.

calendar_id#

pub calendar_id: Option<Id>

Working calendar of the resource. It's read only in CalendarMode::Resource, the default mode, where it must name a calendar in ProjectData::calendars. In CalendarMode::Task and CalendarMode::TaskInherited the id is kept but not resolved. None means the resource has no calendar of its own, and its assignments work on the task calendar.

Default: None.

How a resource calendar combines with a task calendar is covered in Resources and assignments.

Errors#

An invalid field fails the import (Project::solve, schedule) with Err(Error::Input) at the field's path, or rejects the resources.add operation in Project::apply.

Field When it occurs Path
id numeric id isn't finite resources[i].id
capacity value isn't finite or is below 0 resources[i].capacity
calendar_id names no calendar, in CalendarMode::Resource resources[i].calendar_id

Rules that span records, such as unique resource ids, are on ProjectData.

Example#

use plen_core::{
    schedule, AssignmentData, DateTime, ProjectData, ResourceData, SolveOptions, TaskData,
};

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

    let data = ProjectData {
        tasks: vec![
            TaskData {
                start_date: Some(start),
                duration: Some(2.0),
                ..TaskData::new(1)
            },
            TaskData {
                start_date: Some(start),
                duration: Some(3.0),
                ..TaskData::new(2)
            },
        ],
        resources: vec![ResourceData {
            id: "team".into(),
            capacity: Some(2.0),
            calendar_id: None,
        }],
        assignments: vec![
            AssignmentData {
                id: None,
                task: 1.into(),
                resource: "team".into(),
                value: 1.0,
                offset: None,
                duration: None,
            },
            AssignmentData {
                id: None,
                task: 2.into(),
                resource: "team".into(),
                value: 1.0,
                offset: None,
                duration: None,
            },
        ],
        ..Default::default()
    };

    let result = schedule(data, &SolveOptions::default())?;
    // Two parallel full-time assignments fit a capacity of 2.0.
    println!("{:?}", result.overallocations);
    Ok(())
}