use desque::serial::*;
use desque::Result;
use desque::{SimState, SimTime};
use rand::SeedableRng;
use rand_distr::{Distribution, Exp};
use rand_pcg::Pcg64;
use std::cmp::Ordering;
use std::ops::Add;
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
struct Time(f64);
impl Eq for Time {}
impl Ord for Time {
fn cmp(&self, other: &Self) -> Ordering {
self.0.partial_cmp(&other.0).unwrap()
}
}
impl SimTime for Time {}
impl Add<f64> for Time {
type Output = Self;
fn add(self, rhs: f64) -> Self::Output {
Self(self.0 + rhs)
}
}
struct Store {
queue_length: usize,
server_busy: bool,
end_time: f64,
rng: Pcg64,
}
impl Store {
fn new(end_time: f64) -> Self {
Self {
queue_length: 0,
server_busy: false,
end_time,
rng: Pcg64::from_rng(&mut rand::rng()),
}
}
}
impl SimState<Time> for Store {
fn is_complete(&self, current_time: &Time) -> bool {
current_time.0 >= self.end_time
}
}
#[derive(Debug)]
struct ArrivalEvent {}
impl ArrivalEvent {
fn schedule(sim: &mut Simulation<Store, Time>) -> Result {
let distribution = Exp::new(1.0 / 30.0).unwrap();
let next_arrival_delay = distribution.sample(&mut sim.state_mut().rng);
let next_arrival_time = *sim.current_time() + next_arrival_delay;
sim.schedule(ArrivalEvent {}, next_arrival_time)
}
fn schedule_first(sim: &mut Simulation<Store, Time>) -> Result {
let distribution = Exp::new(1.0 / 30.0).unwrap();
let next_arrival_delay = distribution.sample(&mut sim.state_mut().rng);
let next_arrival_time = *sim.current_time() + next_arrival_delay;
sim.schedule(Self {}, next_arrival_time)
}
}
impl Event<Store, Time> for ArrivalEvent {
fn execute(&mut self, sim: &mut Simulation<Store, Time>) -> Result {
println!("Handling customer arrival at time {:.3}...", sim.current_time().0);
if sim.state().server_busy {
println!(
"Server is occupied with prior customer. Getting in line behind {} other customers.",
sim.state().queue_length,
);
sim.state_mut().queue_length += 1;
} else {
println!("Server is idle; moving to counter.");
sim.state_mut().server_busy = true;
ServiceEvent::schedule(sim)?;
}
ArrivalEvent::schedule(sim)?;
Ok(())
}
}
#[derive(Debug)]
struct ServiceEvent {}
impl ServiceEvent {
fn schedule(sim: &mut Simulation<Store, Time>) -> Result {
let distribution = Exp::new(1.0 / 20.0).unwrap();
let service_length = distribution.sample(&mut sim.state_mut().rng);
let service_completion_time = *sim.current_time() + service_length;
sim.schedule(ServiceEvent {}, service_completion_time)
}
}
impl Event<Store, Time> for ServiceEvent {
fn execute(&mut self, sim: &mut Simulation<Store, Time>) -> Result {
println!(
"Completed service for customer. Checking queue at time {:.3}...",
sim.current_time().0,
);
if sim.state().queue_length == 0 {
println!("Queue empty! Waiting for next arrival.");
sim.state_mut().server_busy = false;
} else {
sim.state_mut().queue_length -= 1;
println!(
"Beginning service for next customer. {} remain in the queue.",
sim.state().queue_length,
);
ServiceEvent::schedule(sim)?;
}
Ok(())
}
}
fn main() {
let store = Store::new(540.0);
let mut sim = Simulation::new(store, Time(0.0));
ArrivalEvent::schedule_first(&mut sim).unwrap();
sim.run().unwrap();
}