use web_time::Instant;
use super::{PUMP_BUDGET_MS, Pace, SimLoop};
use crate::fault::Fault;
pub struct Driver<L: SimLoop> {
sim: L,
next_pump_at: Instant,
finished: bool,
}
impl<L: SimLoop> std::fmt::Debug for Driver<L> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Driver")
.field("finished", &self.finished)
.finish_non_exhaustive()
}
}
impl<L: SimLoop> Driver<L> {
pub fn spawn(mut sim: L, on_fault: impl FnOnce(Fault) + 'static) -> Self {
drop(on_fault);
sim.start();
Self {
sim,
next_pump_at: Instant::now(),
finished: false,
}
}
pub fn send(&mut self, cmd: L::Command) {
if self.finished {
return;
}
self.finished = self.sim.handle_command(cmd);
self.next_pump_at = Instant::now();
}
pub fn update(&mut self, _dt: f64) {
if self.finished {
return;
}
let start = Instant::now();
if start < self.next_pump_at {
return;
}
loop {
match self.sim.pump() {
Pace::Idle => {
self.next_pump_at = start;
return;
}
Pace::After(wait) => {
self.next_pump_at = Instant::now() + wait;
return;
}
Pace::Now => {
if start.elapsed().as_secs_f64() * 1000.0 >= PUMP_BUDGET_MS {
self.next_pump_at = start;
return;
}
}
}
}
}
pub fn shutdown(&mut self, cmd: L::Command) {
self.send(cmd);
}
}
#[cfg(test)]
mod tests {
use std::time::Duration;
use super::Driver;
use crate::runner::{Pace, SimLoop};
struct Capped {
pumps: u32,
commands: u32,
}
impl SimLoop for Capped {
type Command = bool;
fn handle_command(&mut self, stop: bool) -> bool {
self.commands += 1;
stop
}
fn pump(&mut self) -> Pace {
self.pumps += 1;
Pace::After(Duration::from_secs(1))
}
}
fn driver() -> Driver<Capped> {
Driver::spawn(Capped { pumps: 0, commands: 0 }, |_| {})
}
#[test]
fn a_command_makes_the_next_pump_due() {
let mut driver = driver();
driver.update(0.0);
assert_eq!(driver.sim.pumps, 1);
driver.update(0.0);
assert_eq!(driver.sim.pumps, 1);
driver.send(false);
driver.update(0.0);
assert_eq!(driver.sim.pumps, 2, "the command waited out the old deadline");
}
#[test]
fn shutdown_stops_the_pumping() {
let mut driver = driver();
driver.shutdown(true);
driver.update(0.0);
assert_eq!(driver.sim.pumps, 0);
assert_eq!(driver.sim.commands, 1);
}
}