[Canonical page](<https://docs.dhtmlx.com/planning-engine/rust/api/core/evaluate/candidate/>)
[Full documentation index](<https://docs.dhtmlx.com/planning-engine/llms.txt>)


# Candidate

One alternative edit to score: an id and the [`SchedulingChanges`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/changes/scheduling-changes.md>) to try. Build a slice of candidates and pass it to [`Project::evaluate`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/project.md#evaluate>) or [`Project::evaluate_with`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/project.md#evaluate_with>).

## Declaration

```rust
#[derive(Clone, Debug)]
pub struct Candidate {
    pub id: Id,
    pub changes: SchedulingChanges,
}
```

`Candidate` doesn't implement `Default`. Build it with a struct literal.

## Fields

| Field | Type | Description |
|---|---|---|
| `id` | [`Id`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/data/id.md>) | Label for the candidate. Copied unchanged into [`CandidateResult::id`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/evaluate/candidate-result.md>). Uniqueness isn't checked. |
| `changes` | [`SchedulingChanges`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/changes/scheduling-changes.md>) | Edits to apply to the copy before scheduling it. |

For how a stale `changes.baseline_id` or a rejected operation in `changes` is reported, see [`Project::evaluate`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/project.md#evaluate>) and [`CandidateResult::error`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/evaluate/candidate-result.md>).

## Example

Score two ways to staff task `1`: assign `dev1` or assign `dev2`.

```rust
use plen_core::{
    AssignmentData, Candidate, DateTime, EvaluateOptions, Project, ProjectData,
    ProjectOptions, ResourceData, SchedulingChanges, SolveOptions, 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)
        }],
        resources: ["dev1", "dev2"]
            .iter()
            .map(|id| ResourceData { id: (*id).into(), capacity: None, calendar_id: None })
            .collect(),
        ..Default::default()
    };

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

    let candidates: Vec<Candidate> = ["dev1", "dev2"]
        .iter()
        .map(|dev| {
            let mut changes = SchedulingChanges::default();
            changes.assignments.add.push(AssignmentData {
                id: None,
                task: 1.into(),
                resource: (*dev).into(),
                value: 1.0,
                offset: None,
                duration: None,
            });
            Candidate { id: (*dev).into(), changes }
        })
        .collect();

    let result = project.evaluate(&candidates, &EvaluateOptions::default())?;
    for c in &result.candidates {
        println!("{:?}: cost {:?}", c.id, c.cost);
    }
    Ok(())
}
```

## Related

- [`CandidateResult`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/evaluate/candidate-result.md>) - the score or error returned for each candidate
- [`EvaluateOptions`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/evaluate/evaluate-options.md>) - options applied to every candidate in the call
- [`Project::evaluate`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/project.md#evaluate>) - the call that scores a slice of candidates
- [Evaluating Alternatives](<https://docs.dhtmlx.com/planning-engine/rust/resources-and-assignment/evaluating-alternatives.md#candidates>) - how to build and score a set of candidates
