cog_task/action/core/
timer.rs1use crate::action::{Action, Props, StatefulAction, INFINITE};
2use crate::comm::{QWriter, Signal, SignalId};
3use crate::resource::{IoManager, LoggerSignal, ResourceManager};
4use crate::server::{AsyncSignal, Config, State, SyncSignal};
5use eyre::{eyre, Error, Result};
6use serde::{Deserialize, Serialize};
7use serde_cbor::Value;
8use std::collections::BTreeSet;
9use std::time::Instant;
10
11#[derive(Debug, Deserialize, Serialize)]
12pub struct Timer {
13 #[serde(default)]
14 name: String,
15 #[serde(default)]
16 out_duration: SignalId,
17}
18
19stateful!(Timer {
20 name: String,
21 out_duration: SignalId,
22 since: Instant,
23});
24
25impl Action for Timer {
26 #[inline]
27 fn out_signals(&self) -> BTreeSet<SignalId> {
28 BTreeSet::from([self.out_duration])
29 }
30
31 fn init(self) -> Result<Box<dyn Action>>
32 where
33 Self: 'static + Sized,
34 {
35 if self.name.is_empty() && self.out_duration == 0 {
36 Err(eyre!(
37 "`Timer` without a `name` or `out_duration` is useless."
38 ))
39 } else {
40 Ok(Box::new(self))
41 }
42 }
43
44 #[inline(always)]
45 fn stateful(
46 &self,
47 _io: &IoManager,
48 _res: &ResourceManager,
49 _config: &Config,
50 _sync_writer: &QWriter<SyncSignal>,
51 _async_writer: &QWriter<AsyncSignal>,
52 ) -> Result<Box<dyn StatefulAction>> {
53 Ok(Box::new(StatefulTimer {
54 done: false,
55 name: self.name.clone(),
56 out_duration: self.out_duration,
57 since: Instant::now(),
58 }))
59 }
60}
61
62impl StatefulAction for StatefulTimer {
63 impl_stateful!();
64
65 fn props(&self) -> Props {
66 INFINITE.into()
67 }
68
69 fn start(
70 &mut self,
71 _sync_writer: &mut QWriter<SyncSignal>,
72 _async_writer: &mut QWriter<AsyncSignal>,
73 _state: &State,
74 ) -> Result<Signal, Error> {
75 self.since = Instant::now();
76 Ok(Signal::none())
77 }
78
79 fn stop(
80 &mut self,
81 _sync_writer: &mut QWriter<SyncSignal>,
82 async_writer: &mut QWriter<AsyncSignal>,
83 _state: &State,
84 ) -> Result<Signal> {
85 let duration = Instant::now() - self.since;
86 if !self.name.is_empty() {
87 async_writer.push(LoggerSignal::Append(
88 "timer".to_owned(),
89 (self.name.clone(), Value::Text(format!("{duration:?}"))),
90 ));
91 }
92
93 if self.out_duration > 0 {
94 Ok(vec![(self.out_duration, Value::Float(duration.as_secs_f64()))].into())
95 } else {
96 Ok(Signal::none())
97 }
98 }
99}