use std::time::Duration;
use crate::response::{Response, TimerCommand};
pub trait TimerRuntime {
type TimerId;
fn set_timer(&mut self, id: Self::TimerId, duration: Duration);
fn kill_timer(&mut self, id: Self::TimerId);
}
pub trait ActionExecutor {
type Action;
fn execute(&mut self, actions: &[Self::Action]);
}
pub fn dispatch<A, T: Copy + Eq + core::fmt::Debug>(
response: &Response<A, T>,
timers: &mut impl TimerRuntime<TimerId = T>,
executor: &mut impl ActionExecutor<Action = A>,
) -> bool {
for cmd in &response.timers {
match *cmd {
TimerCommand::Set { id, duration } => timers.set_timer(id, duration),
TimerCommand::Kill { id } => timers.kill_timer(id),
}
}
if !response.actions.is_empty() {
executor.execute(&response.actions);
}
response.consumed
}
#[cfg(test)]
mod tests {
use super::*;
struct RecordTimers(Vec<TimerCommand<u8>>);
impl TimerRuntime for RecordTimers {
type TimerId = u8;
fn set_timer(&mut self, id: u8, duration: Duration) {
self.0.push(TimerCommand::Set { id, duration });
}
fn kill_timer(&mut self, id: u8) {
self.0.push(TimerCommand::Kill { id });
}
}
struct RecordActions(Vec<&'static str>);
impl ActionExecutor for RecordActions {
type Action = &'static str;
fn execute(&mut self, actions: &[&'static str]) {
self.0.extend_from_slice(actions);
}
}
#[test]
fn dispatch_processes_timers_then_actions() {
let response = Response::emit(vec!["a", "b"])
.with_timer(1, Duration::from_millis(100))
.with_kill_timer(2);
let mut timers = RecordTimers(vec![]);
let mut executor = RecordActions(vec![]);
let consumed = dispatch(&response, &mut timers, &mut executor);
assert!(consumed);
assert_eq!(timers.0.len(), 2);
assert_eq!(executor.0, vec!["a", "b"]);
}
#[test]
fn dispatch_pass_through_returns_false() {
let response: Response<&str, u8> = Response::pass_through();
let mut timers = RecordTimers(vec![]);
let mut executor = RecordActions(vec![]);
let consumed = dispatch(&response, &mut timers, &mut executor);
assert!(!consumed);
assert!(timers.0.is_empty());
assert!(executor.0.is_empty());
}
#[test]
fn dispatch_consume_no_actions() {
let response: Response<&str, u8> =
Response::consume().with_timer(0, Duration::from_millis(50));
let mut timers = RecordTimers(vec![]);
let mut executor = RecordActions(vec![]);
let consumed = dispatch(&response, &mut timers, &mut executor);
assert!(consumed);
assert_eq!(timers.0.len(), 1);
assert!(executor.0.is_empty());
}
}