cog_task/action/core/
view.rs

1use crate::action::{Action, ActionSignal, Props, StatefulAction, DEFAULT, INFINITE, VISUAL};
2use crate::comm::{QWriter, Signal, SignalId};
3use crate::resource::{IoManager, ResourceAddr, ResourceManager};
4use crate::server::{AsyncSignal, Config, State, SyncSignal};
5use crate::util::f64_as_i64;
6use eframe::egui;
7use eyre::{eyre, Context, Result};
8use itertools::Itertools;
9use serde::{Deserialize, Serialize};
10use serde_cbor::Value;
11use std::collections::BTreeSet;
12
13#[derive(Debug, Deserialize, Serialize)]
14pub struct View {
15    #[serde(default)]
16    default: usize,
17    children: Vec<Box<dyn Action>>,
18    in_control: SignalId,
19}
20
21stateful!(View {
22    children: Vec<Box<dyn StatefulAction>>,
23    in_control: SignalId,
24    choice: usize,
25});
26
27impl Action for View {
28    #[inline]
29    fn in_signals(&self) -> BTreeSet<SignalId> {
30        let mut signals = BTreeSet::from([self.in_control]);
31        for c in self.children.iter() {
32            signals.extend(c.in_signals());
33        }
34        signals
35    }
36
37    #[inline]
38    fn out_signals(&self) -> BTreeSet<SignalId> {
39        let mut signals = BTreeSet::new();
40        for c in self.children.iter() {
41            signals.extend(c.out_signals());
42        }
43        signals
44    }
45
46    #[inline]
47    fn resources(&self, config: &Config) -> Vec<ResourceAddr> {
48        self.children
49            .iter()
50            .flat_map(|c| c.resources(config))
51            .unique()
52            .collect()
53    }
54
55    fn stateful(
56        &self,
57        io: &IoManager,
58        res: &ResourceManager,
59        config: &Config,
60        sync_writer: &QWriter<SyncSignal>,
61        async_writer: &QWriter<AsyncSignal>,
62    ) -> Result<Box<dyn StatefulAction>> {
63        let mut children = vec![];
64        for c in self.children.iter() {
65            children.push(c.stateful(io, res, config, sync_writer, async_writer)?);
66        }
67
68        Ok(Box::new(StatefulView {
69            done: false,
70            children,
71            in_control: self.in_control,
72            choice: self.default,
73        }))
74    }
75}
76
77impl StatefulAction for StatefulView {
78    impl_stateful!();
79
80    #[inline]
81    fn props(&self) -> Props {
82        self.children
83            .iter()
84            .fold(DEFAULT, |mut state, c| {
85                let c = c.props();
86                if c.visual() {
87                    state |= VISUAL;
88                }
89                if c.infinite() {
90                    state |= INFINITE;
91                }
92                state
93            })
94            .into()
95    }
96
97    #[inline]
98    fn start(
99        &mut self,
100        sync_writer: &mut QWriter<SyncSignal>,
101        async_writer: &mut QWriter<AsyncSignal>,
102        state: &State,
103    ) -> Result<Signal> {
104        self.choice = match state.get(&self.in_control) {
105            Some(Value::Integer(i)) => {
106                if *i < self.children.len() as i128 {
107                    *i as usize
108                } else {
109                    return Err(eyre!("Branch request is out of bounds."));
110                }
111            }
112            Some(Value::Float(x)) => {
113                let x = f64_as_i64(*x).wrap_err("Non-integer number supplied to view.")?;
114                if (0..self.children.len() as i64).contains(&x) {
115                    x as usize
116                } else {
117                    return Err(eyre!("Branch request is out of bounds."));
118                }
119            }
120            None => self.choice,
121            _ => return Err(eyre!("View control is in invalid state.")),
122        };
123
124        let mut news = vec![];
125        for c in self.children.iter_mut() {
126            news.extend(c.start(sync_writer, async_writer, state)?);
127        }
128
129        Ok(news.into())
130    }
131
132    #[inline]
133    fn update(
134        &mut self,
135        signal: &ActionSignal,
136        sync_writer: &mut QWriter<SyncSignal>,
137        async_writer: &mut QWriter<AsyncSignal>,
138        state: &State,
139    ) -> Result<Signal> {
140        if let ActionSignal::StateChanged(_, signal) = signal {
141            if signal.contains(&self.in_control) {
142                self.choice = match state.get(&self.in_control) {
143                    Some(Value::Integer(i)) => {
144                        if *i < self.children.len() as i128 {
145                            *i as usize
146                        } else {
147                            return Err(eyre!("View request is out of bounds."));
148                        }
149                    }
150                    Some(Value::Float(x)) => {
151                        let x = f64_as_i64(*x).wrap_err("Non-integer number supplied to view.")?;
152                        if (0..self.children.len() as i64).contains(&x) {
153                            x as usize
154                        } else {
155                            return Err(eyre!("View request is out of bounds."));
156                        }
157                    }
158                    None => self.choice,
159                    _ => return Err(eyre!("View control is in invalid state.")),
160                };
161            }
162        }
163
164        let mut news = vec![];
165        for c in self.children.iter_mut() {
166            news.extend(c.update(signal, sync_writer, async_writer, state)?);
167        }
168
169        if self.children[self.choice].is_over()? {
170            self.done = true;
171        }
172
173        Ok(news.into())
174    }
175
176    fn show(
177        &mut self,
178        ui: &mut egui::Ui,
179        sync_writer: &mut QWriter<SyncSignal>,
180        async_writer: &mut QWriter<AsyncSignal>,
181        state: &State,
182    ) -> Result<()> {
183        self.children[self.choice].show(ui, sync_writer, async_writer, state)
184    }
185
186    #[inline]
187    fn stop(
188        &mut self,
189        sync_writer: &mut QWriter<SyncSignal>,
190        async_writer: &mut QWriter<AsyncSignal>,
191        state: &State,
192    ) -> Result<Signal> {
193        let mut news = vec![];
194        for c in self.children.iter_mut() {
195            news.extend(c.stop(sync_writer, async_writer, state)?);
196        }
197        Ok(news.into())
198    }
199}