LinkUpdate#

A partial edit of one existing link: only the fields you set change, the rest keep their current values. Put it in SchedulingChanges::links.update (see SchedulingChanges) and pass the set to Project::apply, Project::preview or an evaluation candidate. Create one with LinkUpdate::new, then set the fields to change.

Declaration#

pub struct LinkUpdate {
    pub id: Id,
    pub source: Patch<Id>,
    pub target: Patch<Id>,
    pub link_type: Patch<LinkType>,
    pub lag: Patch<f64>,
    pub lag_unit: Patch<TimeUnit>,
}

Associated functions#

new#

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

Creates an update for the link with this id. Every other field is Patch::Missing, so the update changes nothing until a field is set.

Parameters

Name Type Description
id impl Into<Id> Id of the link to edit. Accepts &str, String, f64 and i32.

Returns a LinkUpdate with only id set.

Fields#

Each editable field is a Patch; the table shows what Patch::Null does to each. The fields themselves mean the same as on LinkData.

Field Type Patch::Null
id Id not a patch. Selects the link to edit.
source Patch<Id> rejected: a link always has a source.
target Patch<Id> rejected: a link always has a target.
link_type Patch<LinkType> resets to LinkType::Fs.
lag Patch<f64> resets to 0.0.
lag_unit Patch<TimeUnit> clears the unit, so lag is read in config.duration_unit.

id#

pub id: Id

Id of an existing link. The update edits that link and can't change its id.

source, target#

pub source: Patch<Id>
pub target: Patch<Id>

Value(id) moves that end of the link to another task. If the new task doesn't exist or is unscheduled, the update is still applied, but the link is dropped from scheduling and its id is listed in ChangeEffects::dropped_links.

pub link_type: Patch<LinkType>

Which end of source drives which end of target.

lag#

pub lag: Patch<f64>

Working time between the two ends, in the link's lag unit. Negative values are allowed. The value must be finite.

lag_unit#

pub lag_unit: Patch<TimeUnit>

Unit of lag for this link only.

Errors#

An invalid update is listed in ApplyReport::rejected as a RejectedOperation with path links.update[i], and the link stays as it was. An update is rejected when:

  • id names no link in the project: unknown link id
  • source or target is Patch::Null: required field cannot be null
  • lag is NaN or infinite

Example#

Turn link "a" into a start-to-start link with a two-hour lag and leave its tasks as they are:

use plen_core::{
    DateTime, LinkData, LinkType, LinkUpdate, Patch, Project, ProjectData, SchedulingChanges,
    SolveOptions, TaskData, TimeUnit,
};

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(1.0), ..TaskData::new(2) },
        ],
        links: vec![LinkData {
            id: "a".into(),
            source: 1.into(),
            target: 2.into(),
            link_type: LinkType::Fs,
            lag: 0.0,
            lag_unit: None,
        }],
        ..Default::default()
    };

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

    let mut update = LinkUpdate::new("a");
    update.link_type = Patch::Value(LinkType::Ss);
    update.lag = Patch::Value(2.0);
    update.lag_unit = Patch::Value(TimeUnit::Hour);

    let mut changes = SchedulingChanges::default();
    changes.links.update.push(update);

    let report = project.apply(&changes)?;
    for rejected in &report.rejected {
        println!("{}: {}", rejected.path, rejected.message);
    }

    let result = project.solve(None, &options)?;
    for update in &result.updates {
        println!("{update:?}");
    }
    Ok(())
}