1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
use std::{time::{Duration, Instant}};
use crate::{FsmBackend, FsmTimers};
pub struct TimersStd<F>
where F: FsmBackend
{
timers: Vec<(<F as FsmBackend>::Timers, StdTimer)>,
pending_intervals: Option<(<F as FsmBackend>::Timers, usize)>
}
#[derive(Debug)]
enum StdTimer {
Timeout { started_at: Instant, duration: Duration },
Interval { started_at: Instant, interval: Duration }
}
impl<F> TimersStd<F>
where F: FsmBackend
{
pub fn new() -> Self {
Self {
timers: vec![],
pending_intervals: None
}
}
}
impl<F> FsmTimers<F> for TimersStd<F>
where F: FsmBackend
{
fn create(&mut self, id: <F as FsmBackend>::Timers, settings: &crate::TimerSettings) -> crate::FsmResult<()> {
self.cancel(id.clone())?;
if settings.renew {
self.timers.push((id, StdTimer::Interval { started_at: Instant::now(), interval: settings.timeout }));
} else {
self.timers.push((id, StdTimer::Timeout { started_at: Instant::now(), duration: settings.timeout }));
}
Ok(())
}
fn cancel(&mut self, id: <F as FsmBackend>::Timers) -> crate::FsmResult<()> {
self.timers.retain(|(timer_id, _)| *timer_id != id);
Ok(())
}
fn get_triggered_timer(&mut self) -> Option<<F as FsmBackend>::Timers> {
if let Some((id, mut times)) = self.pending_intervals.take() {
times -= 1;
if times > 0 {
self.pending_intervals = Some((id.clone(), times));
}
return Some(id);
}
let mut timed_out_idx = None;
let now = Instant::now();
for (idx, (timer_id, timer)) in self.timers.iter_mut().enumerate() {
match timer {
StdTimer::Timeout { started_at, duration } if now.duration_since(*started_at) >= *duration => {
timed_out_idx = Some(idx);
break;
},
StdTimer::Interval { ref mut started_at, interval } if now.duration_since(*started_at) >= *interval => {
let t = now.duration_since(*started_at);
let times = ((t.as_secs_f32() / interval.as_secs_f32()).floor() as usize) - 1;
if times > 0 {
self.pending_intervals = Some((timer_id.clone(), times));
}
*started_at = now;
return Some(timer_id.clone());
},
_ => ()
}
}
if let Some(idx) = timed_out_idx {
let (id, _) = self.timers.remove(idx);
return Some(id);
}
None
}
}