ApplyReport#

The outcome of one Project::apply call. It lists which operations of the SchedulingChanges batch were accepted, which were rejected, what the accepted ones removed, generated or dropped, and whether the project now needs a full resync. A rejected operation is reported here, not as an Err.

Declaration#

#[derive(Clone, Debug, Default, PartialEq)]
pub struct ApplyReport {
    pub applied: Vec<AppliedOperation>,
    pub rejected: Vec<RejectedOperation>,
    pub effects: ChangeEffects,
    pub needs_resync: bool,
    pub revision: u64,
}

With the serde feature, ApplyReport implements Serialize and Deserialize with camelCase field names (needsResync).

Fields#

applied#

pub applied: Vec<AppliedOperation>

Operations that took effect, in the order apply ran them.

rejected#

pub rejected: Vec<RejectedOperation>

Operations that were refused, in the same order. A rejected operation leaves no partial edit. Empty when the whole batch was accepted.

effects#

pub effects: ChangeEffects

Ids removed, generated or dropped as a result of the accepted operations.

needs_resync#

pub needs_resync: bool

true when rejected isn't empty. See Project::apply for what the project accepts while it's set.

revision#

pub revision: u64

The project's state revision after this call. Every apply raises it, so a larger value from the same Project means a later state.

Every operation of the batch appears in exactly one of applied and rejected. For the order operations run in, see SchedulingChanges.

Example#

Accept one edit, reject another, then resync.

use plen_core::{
    DateTime, Patch, Project, ProjectData, ProjectOptions, SchedulingChanges, SolveOptions,
    TaskData, TaskUpdate,
};

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)
        }],
        ..Default::default()
    };

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

    let mut changes = SchedulingChanges::default();
    let mut done = TaskUpdate::new(1);
    done.progress = Patch::Value(1.0);
    changes.tasks.update.push(done);
    let mut missing = TaskUpdate::new(99);
    missing.duration = Patch::Value(3.0);
    changes.tasks.update.push(missing);

    let report = project.apply(&changes)?;
    for op in &report.applied {
        println!("applied {}", op.path); // applied tasks.update[0]
    }
    for op in &report.rejected {
        println!("rejected {}: {}", op.path, op.message); // rejected tasks.update[1]: unknown task id
    }

    if report.needs_resync {
        project.solve(Some(data), &SolveOptions::default())?;
    } else {
        project.solve(None, &SolveOptions::default())?;
    }
    Ok(())
}