cog_task/action/core/
timer.rs

1use 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}