plato_engine_block/
alarm.rs1pub type AlarmCondition = Box<dyn Fn(&[(String, f64)]) -> bool + Send + Sync>;
5
6#[derive(Debug, Clone, PartialEq)]
8pub enum AlarmState {
9 Idle,
11 Active { since_tick: u64 },
13 Cooldown { until_tick: u64 },
15}
16
17pub struct AlarmRule {
19 pub name: String,
20 pub condition: AlarmCondition,
21 pub cooldown_ticks: u64,
23 pub state: AlarmState,
25 pub last_fired_tick: u64,
27}
28
29impl AlarmRule {
30 pub fn new(
31 name: impl Into<String>,
32 condition: AlarmCondition,
33 cooldown_ticks: u64,
34 ) -> Self {
35 AlarmRule {
36 name: name.into(),
37 condition,
38 cooldown_ticks,
39 state: AlarmState::Idle,
40 last_fired_tick: 0,
41 }
42 }
43
44 pub fn evaluate(&mut self, data: &[(String, f64)], current_tick: u64) -> bool {
47 let triggered = (self.condition)(data);
48
49 match &self.state {
50 AlarmState::Idle => {
51 if triggered {
52 self.state = AlarmState::Active { since_tick: current_tick };
53 self.last_fired_tick = current_tick;
54 return true;
55 }
56 }
57 AlarmState::Active { since_tick: _ } => {
58 if !triggered {
59 self.state = AlarmState::Cooldown {
60 until_tick: current_tick + self.cooldown_ticks,
61 };
62 }
63 }
64 AlarmState::Cooldown { until_tick } => {
65 if current_tick >= *until_tick {
66 if triggered {
67 self.state = AlarmState::Active { since_tick: current_tick };
68 self.last_fired_tick = current_tick;
69 return true;
70 } else {
71 self.state = AlarmState::Idle;
72 }
73 }
74 }
75 }
76 false
77 }
78
79 pub fn reset(&mut self) {
81 self.state = AlarmState::Idle;
82 }
83}
84
85impl core::fmt::Debug for AlarmRule {
86 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
87 f.debug_struct("AlarmRule")
88 .field("name", &self.name)
89 .field("cooldown_ticks", &self.cooldown_ticks)
90 .field("state", &self.state)
91 .finish()
92 }
93}