cog_task/action/core/
logger.rs

1use crate::action::{Action, ActionSignal, 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, Result};
6use serde::{Deserialize, Serialize};
7use std::collections::{BTreeMap, BTreeSet};
8
9#[derive(Debug, Deserialize, Serialize)]
10pub struct Logger {
11    group: String,
12    in_mapping: BTreeMap<SignalId, String>,
13}
14
15stateful!(Logger {
16    group: String,
17    in_mapping: BTreeMap<SignalId, String>,
18});
19
20impl Action for Logger {
21    #[inline]
22    fn in_signals(&self) -> BTreeSet<SignalId> {
23        self.in_mapping.keys().cloned().collect()
24    }
25
26    fn init(self) -> Result<Box<dyn Action>>
27    where
28        Self: 'static + Sized,
29    {
30        if self.group.is_empty() {
31            Err(eyre!("Logger's `group` cannot be empty."))
32        } else if self.in_mapping.is_empty() {
33            Err(eyre!("Logger without `in_mapping` is useless."))
34        } else {
35            Ok(Box::new(self))
36        }
37    }
38
39    fn stateful(
40        &self,
41        _io: &IoManager,
42        _res: &ResourceManager,
43        _config: &Config,
44        _sync_writer: &QWriter<SyncSignal>,
45        _async_writer: &QWriter<AsyncSignal>,
46    ) -> Result<Box<dyn StatefulAction>> {
47        Ok(Box::new(StatefulLogger {
48            done: false,
49            group: self.group.clone(),
50            in_mapping: self.in_mapping.clone(),
51        }))
52    }
53}
54
55impl StatefulAction for StatefulLogger {
56    impl_stateful!();
57
58    fn props(&self) -> Props {
59        INFINITE.into()
60    }
61
62    fn update(
63        &mut self,
64        signal: &ActionSignal,
65        _sync_writer: &mut QWriter<SyncSignal>,
66        async_writer: &mut QWriter<AsyncSignal>,
67        state: &State,
68    ) -> Result<Signal> {
69        let mut entries = vec![];
70        if let ActionSignal::StateChanged(_, signal) = signal {
71            for id in signal {
72                if let Some(name) = self.in_mapping.get(id) {
73                    if let Some(value) = state.get(id) {
74                        entries.push((name.clone(), value.clone()));
75                    }
76                }
77            }
78        }
79
80        async_writer.push(LoggerSignal::Extend(self.group.clone(), entries));
81        Ok(Signal::none())
82    }
83}