tick_machine/
lib.rs

1use std::{
2    fmt::Debug,
3    time::{Duration, Instant},
4};
5
6pub trait Tick {
7    fn try_tick(&mut self);
8}
9
10pub struct TickState {
11    start: Instant,
12    last_tick: Duration,
13    tick: Duration,
14}
15
16impl Debug for TickState {
17    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18        f.debug_struct("TickMachine")
19            .field("tick", &self.tick)
20            .finish()
21    }
22}
23
24impl TickState {
25    pub fn new(tick: Duration) -> Self {
26        Self {
27            start: Instant::now(),
28            last_tick: Duration::ZERO,
29            tick,
30        }
31    }
32
33    pub fn try_tick<F>(&mut self, f: F)
34    where
35        F: FnOnce(),
36    {
37        if self.start.elapsed() - self.last_tick >= self.tick {
38            f();
39            self.last_tick += self.tick;
40        }
41    }
42}
43
44pub struct TickMachine<F> {
45    f: F,
46    tick: TickState,
47}
48
49impl<F: Fn()> TickMachine<F> {
50    pub fn new(tick: TickState, f: F) -> TickMachine<F> {
51        TickMachine { f, tick }
52    }
53}
54
55impl<F: Fn()> Tick for TickMachine<F> {
56    fn try_tick(&mut self) {
57        self.tick.try_tick(|| (self.f)());
58    }
59}
60
61#[cfg(test)]
62mod test {
63    use std::time::Duration;
64
65    use crate::{Tick, TickMachine, TickState};
66
67    #[test]
68    fn test() {
69        let tick = Duration::from_millis(50);
70        let tick = TickState::new(tick);
71        let mut machine = TickMachine::new(tick, || {});
72        machine.try_tick();
73    }
74}