cog_task/action/core/
until.rs

1use crate::action::{Action, ActionSignal, Props, StatefulAction, INFINITE};
2use crate::comm::{QWriter, Signal, SignalId};
3use crate::resource::{IoManager, ResourceAddr, ResourceManager};
4use crate::server::{AsyncSignal, Config, State, SyncSignal};
5use eframe::egui::Ui;
6use eyre::{eyre, Result};
7use serde::{Deserialize, Serialize};
8use serde_cbor::Value;
9use std::collections::BTreeSet;
10
11#[derive(Debug, Deserialize, Serialize)]
12pub struct Until {
13    inner: Box<dyn Action>,
14    #[serde(default)]
15    in_condition: SignalId,
16    #[serde(default)]
17    in_event: SignalId,
18}
19
20stateful!(Until {
21    inner: Box<dyn StatefulAction>,
22    in_condition: SignalId,
23    in_event: SignalId,
24});
25
26impl Action for Until {
27    fn init(self) -> Result<Box<dyn Action>>
28    where
29        Self: 'static + Sized,
30    {
31        if self.in_event == 0 && self.in_condition == 0 {
32            Err(eyre!(
33                "At least one of `in_event` and ``in_condition` have to be set for Until."
34            ))
35        } else {
36            Ok(Box::new(self))
37        }
38    }
39
40    fn in_signals(&self) -> BTreeSet<SignalId> {
41        let mut signals = BTreeSet::from([self.in_event, self.in_condition]);
42        signals.extend(self.inner.out_signals());
43        signals
44    }
45
46    fn out_signals(&self) -> BTreeSet<SignalId> {
47        self.inner.out_signals()
48    }
49
50    fn resources(&self, config: &Config) -> Vec<ResourceAddr> {
51        self.inner.resources(config)
52    }
53
54    fn stateful(
55        &self,
56        io: &IoManager,
57        res: &ResourceManager,
58        config: &Config,
59        sync_writer: &QWriter<SyncSignal>,
60        async_writer: &QWriter<AsyncSignal>,
61    ) -> Result<Box<dyn StatefulAction>> {
62        Ok(Box::new(StatefulUntil {
63            done: false,
64            inner: self
65                .inner
66                .stateful(io, res, config, sync_writer, async_writer)?,
67            in_condition: self.in_condition,
68            in_event: self.in_event,
69        }))
70    }
71}
72
73impl StatefulAction for StatefulUntil {
74    impl_stateful!();
75
76    fn props(&self) -> Props {
77        (self.inner.props().bits() & !INFINITE).into()
78    }
79
80    fn start(
81        &mut self,
82        sync_writer: &mut QWriter<SyncSignal>,
83        async_writer: &mut QWriter<AsyncSignal>,
84        state: &State,
85    ) -> Result<Signal> {
86        let mut done = false;
87        if let Some(&Value::Bool(true)) = state.get(&self.in_condition) {
88            done = true;
89        }
90        if state.contains_key(&self.in_event) {
91            done = true;
92        }
93
94        if done {
95            self.done = true;
96            sync_writer.push(SyncSignal::UpdateGraph);
97            Ok(Signal::none())
98        } else {
99            self.inner.start(sync_writer, async_writer, state)
100        }
101    }
102
103    fn update(
104        &mut self,
105        signal: &ActionSignal,
106        sync_writer: &mut QWriter<SyncSignal>,
107        async_writer: &mut QWriter<AsyncSignal>,
108        state: &State,
109    ) -> Result<Signal> {
110        let mut done = false;
111        if let ActionSignal::StateChanged(_, signal) = signal {
112            for id in signal {
113                if id == &self.in_event {
114                    done = true;
115                } else if id == &self.in_condition {
116                    done |= match state.get(&self.in_condition) {
117                        None => false,
118                        Some(Value::Bool(c)) => *c,
119                        Some(Value::Integer(i)) => *i > 0,
120                        Some(Value::Float(f)) => *f > 0.0,
121                        Some(v) => {
122                            return Err(eyre!(
123                                "Invalid value ({v:?}) supplied as condition for Until."
124                            ))
125                        }
126                    };
127                }
128            }
129        }
130
131        if done {
132            self.done = true;
133            sync_writer.push(SyncSignal::UpdateGraph);
134            Ok(Signal::none())
135        } else {
136            self.inner.update(signal, sync_writer, async_writer, state)
137        }
138    }
139
140    fn show(
141        &mut self,
142        ui: &mut Ui,
143        sync_writer: &mut QWriter<SyncSignal>,
144        async_writer: &mut QWriter<AsyncSignal>,
145        state: &State,
146    ) -> Result<()> {
147        self.inner.show(ui, sync_writer, async_writer, state)
148    }
149
150    fn stop(
151        &mut self,
152        sync_writer: &mut QWriter<SyncSignal>,
153        async_writer: &mut QWriter<AsyncSignal>,
154        state: &State,
155    ) -> Result<Signal> {
156        self.inner.stop(sync_writer, async_writer, state)
157    }
158}