cog_task/action/core/
timeout.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 crate::util::spin_sleeper;
6use eframe::egui::Ui;
7use eyre::Result;
8use serde::{Deserialize, Serialize};
9use std::collections::BTreeSet;
10use std::sync::{Arc, Mutex};
11use std::thread;
12use std::time::Duration;
13
14#[derive(Debug, Deserialize, Serialize)]
15pub struct Timeout(f32, Box<dyn Action>);
16
17stateful!(Timeout {
18    duration: Duration,
19    timeout_over: Arc<Mutex<bool>>,
20    inner: Box<dyn StatefulAction>,
21});
22
23impl Action for Timeout {
24    #[inline]
25    fn in_signals(&self) -> BTreeSet<SignalId> {
26        self.1.in_signals()
27    }
28
29    #[inline]
30    fn out_signals(&self) -> BTreeSet<SignalId> {
31        self.1.out_signals()
32    }
33
34    #[inline(always)]
35    fn resources(&self, config: &Config) -> Vec<ResourceAddr> {
36        self.1.resources(config)
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        let inner = self
48            .1
49            .stateful(io, res, config, sync_writer, async_writer)?;
50
51        Ok(Box::new(StatefulTimeout {
52            done: inner.is_over()?,
53            duration: Duration::from_secs_f32(self.0),
54            timeout_over: Arc::new(Mutex::new(false)),
55            inner,
56        }))
57    }
58}
59
60impl StatefulAction for StatefulTimeout {
61    impl_stateful!();
62
63    fn props(&self) -> Props {
64        let bits = self.inner.props().bits();
65        (bits & !INFINITE).into()
66    }
67
68    fn start(
69        &mut self,
70        sync_writer: &mut QWriter<SyncSignal>,
71        async_writer: &mut QWriter<AsyncSignal>,
72        state: &State,
73    ) -> Result<Signal> {
74        if self.done {
75            sync_writer.push(SyncSignal::UpdateGraph);
76            Ok(Signal::none())
77        } else {
78            let news = self.inner.start(sync_writer, async_writer, state)?;
79
80            let dur = self.duration;
81            let timeout_over = self.timeout_over.clone();
82            let mut sync_writer = sync_writer.clone();
83            thread::spawn(move || {
84                spin_sleeper().sleep(dur);
85                *timeout_over.lock().unwrap() = true;
86                sync_writer.push(SyncSignal::UpdateGraph);
87            });
88
89            Ok(news)
90        }
91    }
92
93    fn update(
94        &mut self,
95        signal: &ActionSignal,
96        sync_writer: &mut QWriter<SyncSignal>,
97        async_writer: &mut QWriter<AsyncSignal>,
98        state: &State,
99    ) -> Result<Signal> {
100        let news = self
101            .inner
102            .update(signal, sync_writer, async_writer, state)?;
103        if self.inner.is_over()?
104            || (matches!(signal, ActionSignal::UpdateGraph) && *self.timeout_over.lock().unwrap())
105        {
106            self.done = true;
107        }
108        Ok(news)
109    }
110
111    fn show(
112        &mut self,
113        ui: &mut Ui,
114        sync_writer: &mut QWriter<SyncSignal>,
115        async_writer: &mut QWriter<AsyncSignal>,
116        state: &State,
117    ) -> Result<()> {
118        self.inner.show(ui, sync_writer, async_writer, state)
119    }
120
121    fn stop(
122        &mut self,
123        sync_writer: &mut QWriter<SyncSignal>,
124        async_writer: &mut QWriter<AsyncSignal>,
125        state: &State,
126    ) -> Result<Signal> {
127        self.inner.stop(sync_writer, async_writer, state)
128    }
129}