cog_task/action/core/
merge.rs1use crate::action::{Action, ActionSignal, Props, StatefulAction, INFINITE};
2use crate::comm::{QWriter, Signal, SignalId};
3use crate::resource::{IoManager, 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 Merge {
11 in_many: BTreeSet<SignalId>,
12 out_one: SignalId,
13}
14
15stateful!(Merge {
16 in_many: BTreeSet<SignalId>,
17 out_one: SignalId,
18});
19
20impl Action for Merge {
21 #[inline]
22 fn in_signals(&self) -> BTreeSet<SignalId> {
23 self.in_many.clone()
24 }
25
26 #[inline]
27 fn out_signals(&self) -> BTreeSet<SignalId> {
28 BTreeSet::from([self.out_one])
29 }
30
31 fn init(self) -> Result<Box<dyn Action>>
32 where
33 Self: 'static + Sized,
34 {
35 if self.in_many.is_empty() {
36 Err(eyre!("Merge with no inputs is useless."))
37 } else if self.out_one == 0 {
38 Err(eyre!("Merge without an output is useless."))
39 } else if self.in_many.contains(&self.out_one) {
40 Err(eyre!("Merge output cannot be connected to its input."))
41 } else {
42 Ok(Box::new(self))
43 }
44 }
45
46 fn stateful(
47 &self,
48 _io: &IoManager,
49 _res: &ResourceManager,
50 _config: &Config,
51 _sync_writer: &QWriter<SyncSignal>,
52 _async_writer: &QWriter<AsyncSignal>,
53 ) -> Result<Box<dyn StatefulAction>> {
54 Ok(Box::new(StatefulMerge {
55 done: false,
56 in_many: self.in_many.clone(),
57 out_one: self.out_one,
58 }))
59 }
60}
61
62impl StatefulAction for StatefulMerge {
63 impl_stateful!();
64
65 fn props(&self) -> Props {
66 INFINITE.into()
67 }
68
69 fn update(
70 &mut self,
71 signal: &ActionSignal,
72 _sync_writer: &mut QWriter<SyncSignal>,
73 _async_writer: &mut QWriter<AsyncSignal>,
74 state: &State,
75 ) -> Result<Signal> {
76 if let ActionSignal::StateChanged(_, signal) = signal {
77 let mut news = BTreeMap::new();
78 for id in signal.iter().filter(|&i| self.in_many.contains(i)) {
79 if let Some(value) = state.get(id) {
80 news.insert(self.out_one, value.clone());
81 }
82 }
83
84 Ok(Signal::new(news))
85 } else {
86 Ok(Signal::none())
87 }
88 }
89}