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}