use std::{
collections::{BTreeMap, BTreeSet},
fmt,
hash::{Hash, Hasher},
mem,
sync::{Arc, Weak},
};
use crate::{
active_task::{ActiveTask, ActiveTasks},
get_task_for_agent, AgentId, AgentValue, Domain, StateDiffRef, Task,
};
pub type Node<D> = Arc<NodeInner<D>>;
pub type WeakNode<D> = Weak<NodeInner<D>>;
pub struct NodeInner<D: Domain> {
pub(crate) diff: D::Diff,
pub(crate) active_agent: AgentId,
pub(crate) tick: u64,
pub(crate) tasks: ActiveTasks<D>,
current_values: BTreeMap<AgentId, AgentValue>, }
impl<D: Domain> fmt::Debug for NodeInner<D> {
fn fmt(&self, f: &'_ mut fmt::Formatter) -> fmt::Result {
f.debug_struct("NodeInner")
.field("diff", &self.diff)
.field("agent", &self.active_agent)
.field("tick", &self.tick)
.field("tasks", &self.tasks)
.field("current_values", &self.current_values)
.finish()
}
}
impl<D: Domain> NodeInner<D> {
pub fn new(
initial_state: &D::State,
start_tick: u64,
diff: D::Diff,
active_agent: AgentId,
tick: u64,
tasks: BTreeSet<ActiveTask<D>>,
) -> Self {
let state_diff = StateDiffRef::new(initial_state, &diff);
let mut agents = tasks.iter().map(|task| task.agent).collect();
D::update_visible_agents(start_tick, tick, state_diff, active_agent, &mut agents);
let (tasks, current_values): (ActiveTasks<D>, _) = agents
.into_iter()
.map(|agent| {
get_task_for_agent(&tasks, agent).map_or_else(
|| ActiveTask::new_idle(tick, agent, active_agent),
|task| task.clone(),
)
})
.map(|task| {
let agent = task.agent;
(task, (agent, D::get_current_value(tick, state_diff, agent)))
})
.unzip();
NodeInner {
active_agent,
diff,
tick,
tasks,
current_values,
}
}
pub fn agent(&self) -> AgentId {
self.active_agent
}
pub fn tick(&self) -> u64 {
self.tick
}
pub fn agents(&self) -> BTreeSet<AgentId> {
self.tasks.iter().map(|task| task.agent).collect()
}
pub fn diff(&self) -> &D::Diff {
&self.diff
}
pub fn current_value(&self, agent: AgentId) -> AgentValue {
self.current_values
.get(&agent)
.copied()
.unwrap_or_else(|| AgentValue::new(0.0).unwrap())
}
pub fn current_value_or_compute(&self, agent: AgentId, initial_state: &D::State) -> AgentValue {
self.current_values.get(&agent).copied().unwrap_or_else(|| {
D::get_current_value(
self.tick,
StateDiffRef::new(initial_state, &self.diff),
agent,
)
})
}
pub fn current_values(&self) -> &BTreeMap<AgentId, AgentValue> {
&self.current_values
}
pub fn size(&self, task_size: fn(&dyn Task<D>) -> usize) -> usize {
let mut size = 0;
size += mem::size_of::<Self>();
size += self.current_values.len() * mem::size_of::<(AgentId, f32)>();
for task in &self.tasks {
size += task.size(task_size);
}
size
}
}
impl<D: Domain> Hash for NodeInner<D> {
fn hash<H: Hasher>(&self, hasher: &mut H) {
self.active_agent.hash(hasher);
self.diff.hash(hasher);
self.tasks.hash(hasher);
self.tick.hash(hasher);
}
}
impl<D: Domain> PartialEq for NodeInner<D> {
fn eq(&self, other: &Self) -> bool {
self.active_agent.eq(&other.active_agent)
&& self.diff.eq(&other.diff)
&& self.tasks.eq(&other.tasks)
&& self.tick.eq(&other.tick)
}
}
impl<D: Domain> Eq for NodeInner<D> {}