use std::{
hash::{Hash, Hasher},
num::NonZeroU64,
};
use downcast_rs::{impl_downcast, Downcast};
use crate::{impl_task_boxed_methods, AgentId, Domain, StateDiffRef, StateDiffRefMut};
pub type TaskDuration = u64;
pub fn debug_name_to_filename_safe(debug_name: &str) -> String {
debug_name
.replace(' ', "")
.replace('(', "")
.replace(')', "")
.replace('{', "_")
.replace('}', "")
.replace(' ', "_")
.replace(':', "_")
.replace(',', "_")
}
pub trait Task<D: Domain>: std::fmt::Debug + Downcast + Send + Sync {
fn weight(&self, _tick: u64, _state_diff: StateDiffRef<D>, _agent: AgentId) -> f32 {
1.0
}
fn duration(&self, _tick: u64, _state_diff: StateDiffRef<D>, _agent: AgentId) -> TaskDuration;
fn execute(
&self,
tick: u64,
state_diff: StateDiffRefMut<D>,
agent: AgentId,
) -> Option<Box<dyn Task<D>>>;
fn is_valid(&self, tick: u64, state_diff: StateDiffRef<D>, agent: AgentId) -> bool;
fn display_action(&self) -> D::DisplayAction;
fn box_clone(&self) -> Box<dyn Task<D>>;
fn box_hash(&self, state: &mut dyn Hasher);
#[allow(clippy::borrowed_box)]
fn box_eq(&self, other: &Box<dyn Task<D>>) -> bool;
}
#[derive(Debug, Hash, Clone, PartialEq)]
pub struct IdleTask;
impl<D: Domain> Task<D> for IdleTask {
fn weight(&self, _tick: u64, _state_diff: StateDiffRef<D>, _agent: AgentId) -> f32 {
1f32
}
fn duration(&self, _tick: u64, _state_diff: StateDiffRef<D>, _agent: AgentId) -> TaskDuration {
1
}
fn execute(
&self,
_tick: u64,
_state_diff: StateDiffRefMut<D>,
_agent: AgentId,
) -> Option<Box<dyn Task<D>>> {
None
}
fn is_valid(&self, _tick: u64, _state_diff: StateDiffRef<D>, _agent: AgentId) -> bool {
true
}
fn display_action(&self) -> D::DisplayAction {
D::display_action_task_idle()
}
impl_task_boxed_methods!(D);
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct PlanningTask(
pub NonZeroU64,
);
impl<D: Domain> Task<D> for PlanningTask {
fn weight(&self, _tick: u64, _state_diff: StateDiffRef<D>, _agent: AgentId) -> f32 {
1f32
}
fn duration(&self, _tick: u64, _state_diff: StateDiffRef<D>, _agent: AgentId) -> TaskDuration {
self.0.get()
}
fn execute(
&self,
_tick: u64,
_state_diff: StateDiffRefMut<D>,
_agent: AgentId,
) -> Option<Box<dyn Task<D>>> {
None
}
fn is_valid(&self, _tick: u64, _state_diff: StateDiffRef<D>, _agent: AgentId) -> bool {
true
}
fn display_action(&self) -> D::DisplayAction {
D::display_action_task_planning()
}
impl_task_boxed_methods!(D);
}
impl_downcast!(Task<D> where D: Domain);
impl<D: Domain> Clone for Box<dyn Task<D>> {
fn clone(&self) -> Self {
self.box_clone()
}
}
impl<D: Domain> Hash for Box<dyn Task<D>> {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
self.box_hash(state);
}
}
impl<D: Domain> PartialEq for Box<dyn Task<D>> {
fn eq(&self, other: &Self) -> bool {
self.box_eq(other)
}
}
impl<D: Domain> Eq for Box<dyn Task<D>> {}
#[macro_export]
macro_rules! impl_task_boxed_methods {
($domain: ty) => {
fn box_clone(&self) -> Box<dyn Task<$domain>> {
Box::new(self.clone())
}
fn box_hash(&self, mut state: &mut dyn std::hash::Hasher) {
use std::hash::Hash;
self.hash(&mut state)
}
fn box_eq(&self, other: &Box<dyn Task<$domain>>) -> bool {
other
.downcast_ref::<Self>()
.map_or(false, |other| self.eq(other))
}
};
}