reactor_rt/
timers.rs

1/*
2 * Copyright (c) 2021, TU Dresden.
3 *
4 * Redistribution and use in source and binary forms, with or without modification,
5 * are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice,
8 *    this list of conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 *    this list of conditions and the following disclaimer in the documentation
12 *    and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
21 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
22 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24use std::time::Instant;
25
26use super::*;
27use crate::assembly::{TriggerId, TriggerLike};
28
29/// A timer is conceptually a logical action that may re-schedule
30/// itself periodically.
31///
32/// For periodic timers, a reaction is synthesized which reschedules
33/// the timer.
34pub struct Timer {
35    id: TriggerId,
36
37    /// Minimal duration after the start of the program after
38    /// which the timer starts to trigger.
39    pub offset: Duration,
40
41    /// Period between events emitted by this timer. A period
42    /// of zero means that the timer will trigger exactly once
43    /// after the specified offset.
44    pub period: Duration,
45}
46
47impl Timer {
48    pub(crate) fn new(id: TriggerId, offset: Duration, period: Duration) -> Self {
49        Self { offset, period, id }
50    }
51
52    /// Whether the timer should repeat itself. A period of zero
53    /// means that the timer will trigger exactly once after the
54    /// specified offset.
55    #[inline]
56    pub fn is_periodic(&self) -> bool {
57        !self.period.is_zero()
58    }
59}
60
61impl TriggerLike for Timer {
62    fn get_id(&self) -> TriggerId {
63        self.id
64    }
65}
66
67impl ReactionTrigger<()> for Timer {
68    fn is_present(&self, now: &EventTag, _start: &Instant) -> bool {
69        let elapsed = now.duration_since_start();
70        if elapsed == self.offset {
71            true
72        } else if elapsed < self.offset || !self.is_periodic() {
73            false
74        } else {
75            ((elapsed - self.offset).as_nanos() % self.period.as_nanos()) == 0
76        }
77    }
78
79    #[inline]
80    fn get_value(&self, now: &EventTag, start: &Instant) -> Option<()> {
81        if self.is_present(now, start) {
82            Some(())
83        } else {
84            None
85        }
86    }
87
88    #[inline]
89    fn use_value_ref<O>(&self, now: &EventTag, start: &Instant, action: impl FnOnce(Option<&()>) -> O) -> O {
90        if self.is_present(now, start) {
91            action(Some(&()))
92        } else {
93            action(None)
94        }
95    }
96}