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
90
91
92
93
94
95
96
//! An implementation of timers that relies just on the `Duration`. Has to be called with
//! a reasonable period rate to trigger the timers.

use crate::{FsmBackend, FsmTimers, TimersStorage, AllVariants};
use crate::lib::*;
use Duration;
use arraydeque::{Array, ArrayDeque};

pub struct TimersCore<F, S, Q>
    where F: FsmBackend,
          Q: Array<Item = <F as FsmBackend>::Timers>,
          S: TimersStorage<<F as FsmBackend>::Timers, CoreTimer>
{
    timers: S,
    pending_events: ArrayDeque<Q>,
    _fsm: PhantomData<F>
}

#[derive(Debug)]
pub enum CoreTimer {
    Timeout { time_remaining: Duration },
    Interval { time_remaining: Duration, interval: Duration }
}

impl<F, S, Q> TimersCore<F, S, Q>
    where F: FsmBackend,
    Q: Array<Item = <F as FsmBackend>::Timers>,
    S: TimersStorage<<F as FsmBackend>::Timers, CoreTimer>
{
    pub fn new(timers: S) -> Self {
        Self {
            timers,
            pending_events: ArrayDeque::new(),
            _fsm: PhantomData::default()
        }
    }

    pub fn tick(&mut self, elapsed_since_last_tick: Duration) {
        let iter = <F as FsmBackend>::Timers::iter();
        for id in iter {
            let mut timer = self.timers.get_timer_storage_mut(&id);

            // todo: account for the difference between time remaining and elapsed time, currently we just reset it
            match timer {
                Some(CoreTimer::Timeout { time_remaining}) => {
                    if *time_remaining <= elapsed_since_last_tick {
                        self.pending_events.push_front(id);
                        *timer = None
                    } else {
                        *time_remaining -= elapsed_since_last_tick;
                    }
                },
                Some(CoreTimer::Interval { time_remaining, interval }) => {
                    if *time_remaining <= elapsed_since_last_tick {
                        self.pending_events.push_front(id);
                        *time_remaining = *interval;
                    } else {
                        *time_remaining -= elapsed_since_last_tick;
                    }
                }
                None => {}
            }
        }
    }
}

impl<F, S, Q> FsmTimers<F> for TimersCore<F, S, Q>
    where F: FsmBackend,
    Q: Array<Item = <F as FsmBackend>::Timers>,
    S: TimersStorage<<F as FsmBackend>::Timers, CoreTimer>
{
    fn create(&mut self, id: <F as FsmBackend>::Timers, settings: &crate::TimerSettings) -> crate::FsmResult<()> {
        self.cancel(id.clone());

        if settings.enabled {
            let mut timer = self.timers.get_timer_storage_mut(&id);
            if settings.renew {
                *timer = Some(CoreTimer::Interval { interval: settings.timeout, time_remaining: settings.timeout });
            } else {
                *timer = Some(CoreTimer::Timeout { time_remaining: settings.timeout });
            }
        }
        
        Ok(())
    }

    fn cancel(&mut self, id: <F as FsmBackend>::Timers) -> crate::FsmResult<()> {
        let timer = self.timers.get_timer_storage_mut(&id);
        *timer = None;
        Ok(())
    }

    fn get_triggered_timer(&mut self) -> Option<<F as FsmBackend>::Timers> {
        self.pending_events.pop_back()
    }
}