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


# Roster

A skill-free inventory of the project's accepted state: its scheduled leaf tasks, its resources and its active assignments. [`Project::roster`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/project.md#roster>) returns it. [`plen_assign::slots`](<https://docs.dhtmlx.com/planning-engine/rust/api/assign/slots.md>) builds slots from it.

:::note
`Roster` is native only. It has no serialized form and doesn't implement `Serialize`, even with the `serde` feature.
:::

## Declaration

```rust
#[derive(Clone, Debug, Default, PartialEq)]
pub struct Roster {
    pub tasks: Vec<Id>,
    pub resources: Vec<Id>,
    pub assignments: Vec<RosterAssignment>,
}
```

## Fields

| Field | Type | Description |
|---|---|---|
| `tasks` | `Vec<`[`Id`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/data/id.md>)`>` | Scheduled leaf tasks, in model order. Summary tasks and unscheduled tasks aren't listed. |
| `resources` | `Vec<`[`Id`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/data/id.md>)`>` | All resources, in model order. |
| `assignments` | `Vec<`[`RosterAssignment`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/suggest/roster-assignment.md>)`>` | Active assignments, in model order. Assignments on unscheduled tasks aren't listed. |

Model order is the order of the entries in the accepted [`ProjectData`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/data/project-data.md>).

## Example

The unscheduled task `u` and its assignment `y` are left out.

```rust
use plen_core::{
    AssignmentData, DateTime, Project, ProjectData, ProjectOptions, ResourceData,
    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 booking = |id: &str, task: &str, resource: &str| AssignmentData {
        id: Some(id.into()),
        task: task.into(),
        resource: resource.into(),
        value: 1.0,
        offset: None,
        duration: None,
    };
    let data = ProjectData {
        tasks: vec![
            TaskData { start_date: Some(monday), duration: Some(2.0), ..TaskData::new("a") },
            TaskData {
                start_date: Some(monday),
                duration: Some(1.0),
                unscheduled: true,
                ..TaskData::new("u")
            },
        ],
        resources: ["r1", "r2"]
            .iter()
            .map(|id| ResourceData { id: (*id).into(), capacity: None, calendar_id: None })
            .collect(),
        assignments: vec![booking("x", "a", "r1"), booking("y", "u", "r2")],
        ..Default::default()
    };

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

    let roster = project.roster()?;
    for task in &roster.tasks {
        println!("task {task}"); // task a
    }
    for resource in &roster.resources {
        println!("resource {resource}"); // resource r1, resource r2
    }
    for a in &roster.assignments {
        println!("{}: {} on {}", a.id, a.resource, a.task); // x: r1 on a
    }
    Ok(())
}
```

## Related

- [`Project::roster`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/project.md#roster>) - returns this inventory
- [`plen_assign::slots`](<https://docs.dhtmlx.com/planning-engine/rust/api/assign/slots.md>) - builds slots from it
- [`Slot`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/suggest/slot.md>) - the type built from the roster for auto-assignment
- [Skills and Requirements](<https://docs.dhtmlx.com/planning-engine/rust/resources-and-assignment/skills-and-requirements.md>) - shows how the skill layer reads the roster to build slots
