use std::collections::{BTreeMap, BTreeSet};
use sim_kernel::Symbol;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum NodeStatus {
Idle,
Running,
Ok,
Error,
}
impl NodeStatus {
pub fn token(self) -> &'static str {
match self {
NodeStatus::Idle => "idle",
NodeStatus::Running => "running",
NodeStatus::Ok => "ok",
NodeStatus::Error => "error",
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct RunEvent {
pub at: u64,
pub node: Symbol,
pub kind: Symbol,
pub message: String,
pub edge: Option<(Symbol, Symbol)>,
}
impl RunEvent {
pub fn node(at: u64, node: &str, kind: &str, message: &str) -> Self {
Self {
at,
node: Symbol::new(node),
kind: Symbol::new(kind),
message: message.to_owned(),
edge: None,
}
}
pub fn route(at: u64, from: &str, to: &str) -> Self {
Self {
at,
node: Symbol::new(from),
kind: Symbol::new("route"),
message: format!("{from} -> {to}"),
edge: Some((Symbol::new(from), Symbol::new(to))),
}
}
}
#[derive(Clone, Debug, Default)]
pub struct RunState {
pub statuses: BTreeMap<Symbol, NodeStatus>,
pub counters: BTreeMap<Symbol, u64>,
pub events: Vec<RunEvent>,
pub live_edges: BTreeSet<(Symbol, Symbol)>,
}
impl RunState {
pub fn new() -> Self {
Self::default()
}
pub fn apply_event(&mut self, event: RunEvent) {
*self.counters.entry(event.node.clone()).or_insert(0) += 1;
match &*event.kind.name {
"start" => {
self.statuses
.insert(event.node.clone(), NodeStatus::Running);
}
"ok" => {
self.statuses.insert(event.node.clone(), NodeStatus::Ok);
}
"error" => {
self.statuses.insert(event.node.clone(), NodeStatus::Error);
}
"route" => {
if let Some(edge) = &event.edge {
self.live_edges.insert(edge.clone());
}
}
_ => {}
}
self.events.push(event);
}
pub fn status(&self, node: &Symbol) -> NodeStatus {
self.statuses.get(node).copied().unwrap_or(NodeStatus::Idle)
}
pub fn count(&self, node: &Symbol) -> u64 {
self.counters.get(node).copied().unwrap_or(0)
}
pub fn edge_live(&self, from: &Symbol, to: &Symbol) -> bool {
self.live_edges.contains(&(from.clone(), to.clone()))
}
pub fn events_for(&self, node: &Symbol) -> Vec<&RunEvent> {
self.events
.iter()
.filter(|event| &event.node == node)
.collect()
}
}