npc_engine_core/
active_task.rs

1/*
2 *  SPDX-License-Identifier: Apache-2.0 OR MIT
3 *  © 2020-2022 ETH Zurich and other contributors, see AUTHORS.txt for details
4 */
5
6use crate::{AgentId, Domain, IdleTask, StateDiffRef, Task};
7use std::cmp::Ordering;
8use std::collections::BTreeSet;
9use std::hash::{Hash, Hasher};
10use std::{fmt, mem};
11
12/// A task associated to an agent and that is being processed by the planner.
13pub struct ActiveTask<D: Domain> {
14    /// the end tick of this task
15    pub end: u64,
16    /// the agent executing this task
17    pub agent: AgentId,
18    /// the actual task
19    pub task: Box<dyn Task<D>>,
20}
21/// A set of active tasks.
22///
23/// These tasks are sorted by end time and then by agent, due to the implementation of `cmp` by `ActiveTask`.
24pub type ActiveTasks<D> = BTreeSet<ActiveTask<D>>;
25
26impl<D: Domain> ActiveTask<D> {
27    /// Creates a new active task, computes the end from task and the state_diff.
28    pub fn new(
29        agent: AgentId,
30        task: Box<dyn Task<D>>,
31        tick: u64,
32        state_diff: StateDiffRef<D>,
33    ) -> Self {
34        let end = tick + task.duration(tick, state_diff, agent);
35        ActiveTask { end, agent, task }
36    }
37    /// Creates a new active task with a specified end.
38    pub fn new_with_end(end: u64, agent: AgentId, task: Box<dyn Task<D>>) -> Self {
39        ActiveTask { end, agent, task }
40    }
41    /// Creates a new idle task for agent at a given tick, make sure that it will
42    /// execute in the future considering that we are currently processing active_agent.
43    pub fn new_idle(tick: u64, agent: AgentId, active_agent: AgentId) -> Self {
44        ActiveTask {
45            // Make sure the idle tasks of added agents will not be
46            // executed before the active agent.
47            end: if agent < active_agent { tick + 1 } else { tick },
48            agent,
49            task: Box::new(IdleTask),
50        }
51    }
52    /// The memory footprint of this struct.
53    pub fn size(&self, task_size: fn(&dyn Task<D>) -> usize) -> usize {
54        let mut size = 0;
55        size += mem::size_of::<Self>();
56        size += task_size(&*self.task);
57        size
58    }
59}
60
61/// Returns the task associated to a given agent from an active task set.
62pub(crate) fn get_task_for_agent<D: Domain>(
63    set: &ActiveTasks<D>,
64    agent: AgentId,
65) -> Option<&ActiveTask<D>> {
66    for task in set {
67        if task.agent == agent {
68            return Some(task);
69        }
70    }
71    None
72}
73
74impl<D: Domain> fmt::Debug for ActiveTask<D> {
75    fn fmt(&self, f: &'_ mut fmt::Formatter) -> fmt::Result {
76        f.debug_struct("ActiveTask")
77            .field("end", &self.end)
78            .field("agent", &self.agent)
79            .field("task", &self.task)
80            .finish()
81    }
82}
83
84impl<D: Domain> std::fmt::Display for ActiveTask<D> {
85    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86        write!(f, "{} {:?} ends T{}", self.agent, self.task, self.end)
87    }
88}
89
90impl<D: Domain> Hash for ActiveTask<D> {
91    fn hash<H: Hasher>(&self, state: &mut H) {
92        self.end.hash(state);
93        self.agent.hash(state);
94        self.task.hash(state);
95    }
96}
97
98impl<D: Domain> Clone for ActiveTask<D> {
99    fn clone(&self) -> Self {
100        ActiveTask {
101            end: self.end,
102            agent: self.agent,
103            task: self.task.box_clone(),
104        }
105    }
106}
107
108impl<D: Domain> Ord for ActiveTask<D> {
109    /// Active tasks are ordered first by time of ending, then by agent id
110    fn cmp(&self, other: &Self) -> Ordering {
111        self.end.cmp(&other.end).then(self.agent.cmp(&other.agent))
112    }
113}
114
115impl<D: Domain> PartialOrd for ActiveTask<D> {
116    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
117        Some(self.cmp(other))
118    }
119}
120
121impl<D: Domain> Eq for ActiveTask<D> {}
122
123impl<D: Domain> PartialEq for ActiveTask<D> {
124    fn eq(&self, other: &Self) -> bool {
125        self.end == other.end && self.agent == other.agent && self.task.box_eq(&other.task)
126    }
127}