Slot#

One requirement instance on one task: the task, the resources eligible for it, and the assignment that fills it, if any. Create one with Slot::new, or get a list from plen_assign::slots. Slots are the input of Project::suggest_assignments. A slot lists eligible resources only, never skills.

Declaration#

#[derive(Clone, Debug, PartialEq)]
pub struct Slot {
    pub id: Id,
    pub task: Id,
    pub allowed: Vec<Id>,
    pub value: f64,
    pub assignment: Option<Id>,
}

Slot doesn't implement Default. Start from Slot::new and set other fields with struct update syntax.

Constructors#

new#

pub fn new(id: impl Into<Id>, task: impl Into<Id>, allowed: Vec<Id>) -> Slot

Creates an empty slot with value: 1.0 and assignment: None.

Parameters

Name Type Description
id impl Into<Id> Slot id
task impl Into<Id> Task the slot belongs to
allowed Vec<Id> Eligible resources, in preference order

Returns the new Slot.

Fields#

Field Type Default via new Description
id Id - Unique among the slots of one call. A new assignment that fills the slot gets this id. Echoed in SuggestStep::slot and in the unfilled and invalid lists of SuggestResult.
task Id - A scheduled leaf task.
allowed Vec<Id> - Eligible resources. The order is the tie-break preference. A duplicate entry counts once.
value f64 1.0 Units of a new assignment that fills the slot (1 = 100 %). Must be finite and > 0.
assignment Option<Id> None The active assignment that fills the slot. None = the slot is empty.

Whether the slot is empty, held by a resource outside allowed, or held by a resource in allowed decides its AssignTarget category.

A filled slot's new assignment takes the slot id. To keep that binding on the next run, set assignment: Some(slot_id).

Accepted values#

Project::suggest_assignments checks the slots in input order and returns Error::Input with one of these paths:

Path When
slots[i].id The id repeats another slot's id, or equals an existing assignment id (active or inactive) other than this slot's own assignment
slots[i].task The task is unknown, unscheduled or a summary
slots[i].allowed[j] The resource is unknown
slots[i].value value isn't finite or is <= 0
slots[i].assignment The assignment is unknown, inactive, on another task, or bound by two slots

Serialization#

With the serde feature (cargo add plen-core --features serde), Slot implements Serialize only. assignment is omitted when it's None.

Example#

One empty slot on task 1 at half-time that prefers dev2, and one slot already filled by the assignment review.

use plen_core::{
    AssignmentData, DateTime, Project, ProjectData, ProjectOptions, ResourceData, Slot,
    SolveOptions, SuggestOptions, TaskData,
};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let monday = DateTime::from_ymd_hm(2026, 8, 10, 8, 0).ok_or("invalid date")?;
    let data = ProjectData {
        tasks: vec![
            TaskData { start_date: Some(monday), duration: Some(2.0), ..TaskData::new(1) },
            TaskData { start_date: Some(monday), duration: Some(3.0), ..TaskData::new(2) },
        ],
        resources: ["dev1", "dev2"]
            .iter()
            .map(|id| ResourceData { id: (*id).into(), capacity: None, calendar_id: None })
            .collect(),
        assignments: vec![AssignmentData {
            id: Some("review".into()),
            task: 2.into(),
            resource: "dev1".into(),
            value: 1.0,
            offset: None,
            duration: None,
        }],
        ..Default::default()
    };

    let mut project = Project::new(ProjectOptions::default());
    project.solve(Some(data), &SolveOptions::default())?;

    let slots = vec![
        Slot { value: 0.5, ..Slot::new("build", 1, vec!["dev2".into(), "dev1".into()]) },
        Slot {
            assignment: Some("review".into()),
            ..Slot::new("review", 2, vec!["dev1".into(), "dev2".into()])
        },
    ];

    let result = project.suggest_assignments(&slots, &SuggestOptions::default())?;
    for step in &result.steps {
        println!("{} -> {}", step.slot, step.to_resource);
    }
    Ok(())
}

For how slots are visited, filled and rebalanced, see Suggesting assignments.