use crate::{
BinId, ChargingStationId, EdgeId, EventId, MaintenanceStationId, NodeId, OrderId, RobotId,
ShipmentId, SimTime, SkuId, StationId, TaskId,
};
use rkyv::{Archive, Deserialize, Serialize};
use std::cmp::Ordering;
#[derive(Archive, Deserialize, Serialize, Clone, Debug)]
pub enum SimEvent {
OrderArrival { order_id: OrderId },
TaskAssignment { task_id: TaskId, robot_id: RobotId },
RobotDepartNode {
robot_id: RobotId,
from_node: NodeId,
to_node: NodeId,
edge_id: EdgeId,
},
RobotArriveNode {
robot_id: RobotId,
node_id: NodeId,
from_node: NodeId,
},
StationServiceStart {
robot_id: RobotId,
station_id: StationId,
task_id: TaskId,
},
StationServiceEnd {
robot_id: RobotId,
station_id: StationId,
task_id: TaskId,
},
InventoryUpdate {
sku_id: SkuId,
bin_id: BinId,
delta: i32,
task_id: TaskId,
},
RobotWaitStart {
robot_id: RobotId,
at_node: NodeId,
waiting_for_edge: EdgeId,
},
RobotWaitEnd { robot_id: RobotId, at_node: NodeId },
RobotPickup {
robot_id: RobotId,
task_id: TaskId,
node_id: NodeId,
},
DispatchTasks,
InboundArrival {
shipment_id: ShipmentId,
station_id: StationId,
},
PutawayTaskCreated {
task_id: TaskId,
shipment_id: ShipmentId,
},
OutboundReady { order_id: OrderId },
ShipmentDeparture {
shipment_id: ShipmentId,
station_id: StationId,
},
ReplenishmentTrigger {
sku_id: SkuId,
bin_id: BinId,
current_qty: u32,
threshold: u32,
},
RobotChargingStart {
robot_id: RobotId,
station_id: ChargingStationId,
},
RobotChargingEnd {
robot_id: RobotId,
station_id: ChargingStationId,
energy_charged_wh: f64,
},
RobotLowBattery { robot_id: RobotId, soc: f64 },
MetricsSampleTick,
DeadlockDetected {
robots: Vec<RobotId>,
},
DeadlockResolved {
robots: Vec<RobotId>,
resolver_robot: RobotId,
},
RobotFailure {
robot_id: RobotId,
interrupted_task: Option<TaskId>,
},
RobotMaintenanceDue {
robot_id: RobotId,
operating_hours: f64,
},
MaintenanceStart {
robot_id: RobotId,
station_id: MaintenanceStationId,
is_repair: bool,
},
MaintenanceEnd {
robot_id: RobotId,
station_id: MaintenanceStationId,
is_repair: bool,
duration_s: f64,
},
}
impl SimEvent {
pub fn event_type_name(&self) -> &'static str {
match self {
SimEvent::OrderArrival { .. } => "order_arrival",
SimEvent::TaskAssignment { .. } => "task_assignment",
SimEvent::RobotDepartNode { .. } => "robot_depart_node",
SimEvent::RobotArriveNode { .. } => "robot_arrive_node",
SimEvent::StationServiceStart { .. } => "station_service_start",
SimEvent::StationServiceEnd { .. } => "station_service_end",
SimEvent::InventoryUpdate { .. } => "inventory_update",
SimEvent::RobotWaitStart { .. } => "robot_wait_start",
SimEvent::RobotWaitEnd { .. } => "robot_wait_end",
SimEvent::RobotPickup { .. } => "robot_pickup",
SimEvent::DispatchTasks => "dispatch_tasks",
SimEvent::InboundArrival { .. } => "inbound_arrival",
SimEvent::PutawayTaskCreated { .. } => "putaway_task_created",
SimEvent::OutboundReady { .. } => "outbound_ready",
SimEvent::ShipmentDeparture { .. } => "shipment_departure",
SimEvent::ReplenishmentTrigger { .. } => "replenishment_trigger",
SimEvent::RobotChargingStart { .. } => "robot_charging_start",
SimEvent::RobotChargingEnd { .. } => "robot_charging_end",
SimEvent::RobotLowBattery { .. } => "robot_low_battery",
SimEvent::MetricsSampleTick => "metrics_sample_tick",
SimEvent::DeadlockDetected { .. } => "deadlock_detected",
SimEvent::DeadlockResolved { .. } => "deadlock_resolved",
SimEvent::RobotFailure { .. } => "robot_failure",
SimEvent::RobotMaintenanceDue { .. } => "robot_maintenance_due",
SimEvent::MaintenanceStart { .. } => "maintenance_start",
SimEvent::MaintenanceEnd { .. } => "maintenance_end",
}
}
pub fn robot_id(&self) -> Option<RobotId> {
match self {
SimEvent::TaskAssignment { robot_id, .. } => Some(*robot_id),
SimEvent::RobotDepartNode { robot_id, .. } => Some(*robot_id),
SimEvent::RobotArriveNode { robot_id, .. } => Some(*robot_id),
SimEvent::StationServiceStart { robot_id, .. } => Some(*robot_id),
SimEvent::StationServiceEnd { robot_id, .. } => Some(*robot_id),
SimEvent::RobotWaitStart { robot_id, .. } => Some(*robot_id),
SimEvent::RobotWaitEnd { robot_id, .. } => Some(*robot_id),
SimEvent::RobotPickup { robot_id, .. } => Some(*robot_id),
SimEvent::RobotChargingStart { robot_id, .. } => Some(*robot_id),
SimEvent::RobotChargingEnd { robot_id, .. } => Some(*robot_id),
SimEvent::RobotLowBattery { robot_id, .. } => Some(*robot_id),
SimEvent::DeadlockResolved { resolver_robot, .. } => Some(*resolver_robot),
SimEvent::RobotFailure { robot_id, .. } => Some(*robot_id),
SimEvent::RobotMaintenanceDue { robot_id, .. } => Some(*robot_id),
SimEvent::MaintenanceStart { robot_id, .. } => Some(*robot_id),
SimEvent::MaintenanceEnd { robot_id, .. } => Some(*robot_id),
_ => None,
}
}
pub fn task_id(&self) -> Option<TaskId> {
match self {
SimEvent::TaskAssignment { task_id, .. } => Some(*task_id),
SimEvent::StationServiceStart { task_id, .. } => Some(*task_id),
SimEvent::StationServiceEnd { task_id, .. } => Some(*task_id),
SimEvent::InventoryUpdate { task_id, .. } => Some(*task_id),
SimEvent::RobotPickup { task_id, .. } => Some(*task_id),
SimEvent::PutawayTaskCreated { task_id, .. } => Some(*task_id),
_ => None,
}
}
pub fn shipment_id(&self) -> Option<ShipmentId> {
match self {
SimEvent::InboundArrival { shipment_id, .. } => Some(*shipment_id),
SimEvent::PutawayTaskCreated { shipment_id, .. } => Some(*shipment_id),
SimEvent::ShipmentDeparture { shipment_id, .. } => Some(*shipment_id),
_ => None,
}
}
pub fn charging_station_id(&self) -> Option<ChargingStationId> {
match self {
SimEvent::RobotChargingStart { station_id, .. } => Some(*station_id),
SimEvent::RobotChargingEnd { station_id, .. } => Some(*station_id),
_ => None,
}
}
pub fn maintenance_station_id(&self) -> Option<MaintenanceStationId> {
match self {
SimEvent::MaintenanceStart { station_id, .. } => Some(*station_id),
SimEvent::MaintenanceEnd { station_id, .. } => Some(*station_id),
_ => None,
}
}
}
#[derive(Archive, Deserialize, Serialize, Clone, Debug)]
pub struct ScheduledEvent {
pub id: EventId,
pub time: SimTime,
pub event: SimEvent,
}
impl ScheduledEvent {
pub fn new(id: EventId, time: SimTime, event: SimEvent) -> Self {
Self { id, time, event }
}
}
impl PartialEq for ScheduledEvent {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl Eq for ScheduledEvent {}
impl PartialOrd for ScheduledEvent {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for ScheduledEvent {
fn cmp(&self, other: &Self) -> Ordering {
match other.time.0.partial_cmp(&self.time.0) {
Some(Ordering::Equal) | None => other.id.0.cmp(&self.id.0),
Some(ord) => ord,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_event_ordering() {
let e1 = ScheduledEvent::new(
EventId(1),
SimTime::from_seconds(10.0),
SimEvent::DispatchTasks,
);
let e2 = ScheduledEvent::new(
EventId(2),
SimTime::from_seconds(5.0),
SimEvent::DispatchTasks,
);
assert!(e2 > e1);
}
#[test]
fn test_event_type_name() {
let event = SimEvent::OrderArrival {
order_id: OrderId(1),
};
assert_eq!(event.event_type_name(), "order_arrival");
}
}