cog_task/action/core/
delayed.rs

1use crate::action::{Action, ActionSignal, Props, StatefulAction, DEFAULT};
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 Delayed(f32, Box<dyn Action>);
16
17stateful!(Delayed {
18    duration: Duration,
19    wait_over: Arc<Mutex<bool>>,
20    has_begun: bool,
21    inner: Box<dyn StatefulAction>,
22});
23
24impl Action for Delayed {
25    #[inline]
26    fn in_signals(&self) -> BTreeSet<SignalId> {
27        self.1.in_signals()
28    }
29
30    #[inline]
31    fn out_signals(&self) -> BTreeSet<SignalId> {
32        self.1.out_signals()
33    }
34
35    #[inline(always)]
36    fn resources(&self, config: &Config) -> Vec<ResourceAddr> {
37        self.1.resources(config)
38    }
39
40    fn stateful(
41        &self,
42        io: &IoManager,
43        res: &ResourceManager,
44        config: &Config,
45        sync_writer: &QWriter<SyncSignal>,
46        async_writer: &QWriter<AsyncSignal>,
47    ) -> Result<Box<dyn StatefulAction>> {
48        let inner = self
49            .1
50            .stateful(io, res, config, sync_writer, async_writer)?;
51
52        Ok(Box::new(StatefulDelayed {
53            done: inner.is_over()?,
54            duration: Duration::from_secs_f32(self.0),
55            wait_over: Arc::new(Mutex::new(false)),
56            has_begun: false,
57            inner,
58        }))
59    }
60}
61
62impl StatefulAction for StatefulDelayed {
63    impl_stateful!();
64
65    fn props(&self) -> Props {
66        if self.has_begun {
67            self.inner.props()
68        } else {
69            DEFAULT.into()
70        }
71    }
72
73    fn start(
74        &mut self,
75        sync_writer: &mut QWriter<SyncSignal>,
76        _async_writer: &mut QWriter<AsyncSignal>,
77        _state: &State,
78    ) -> Result<Signal> {
79        if self.done {
80            sync_writer.push(SyncSignal::UpdateGraph);
81        } else {
82            let wait_over = self.wait_over.clone();
83            let dur = self.duration;
84            let mut sync_writer = sync_writer.clone();
85            thread::spawn(move || {
86                spin_sleeper().sleep(dur);
87                *wait_over.lock().unwrap() = true;
88                sync_writer.push(SyncSignal::UpdateGraph);
89            });
90        }
91        Ok(Signal::none())
92    }
93
94    fn update(
95        &mut self,
96        signal: &ActionSignal,
97        sync_writer: &mut QWriter<SyncSignal>,
98        async_writer: &mut QWriter<AsyncSignal>,
99        state: &State,
100    ) -> Result<Signal> {
101        if *self.wait_over.lock().unwrap() {
102            let news = if !self.has_begun {
103                self.has_begun = true;
104                self.inner.start(sync_writer, async_writer, state)?
105            } else {
106                self.inner
107                    .update(signal, sync_writer, async_writer, state)?
108            };
109
110            if self.inner.is_over()? {
111                self.done = true;
112            }
113            Ok(news)
114        } else {
115            Ok(Signal::none())
116        }
117    }
118
119    fn show(
120        &mut self,
121        ui: &mut Ui,
122        sync_writer: &mut QWriter<SyncSignal>,
123        async_writer: &mut QWriter<AsyncSignal>,
124        state: &State,
125    ) -> Result<()> {
126        if self.has_begun {
127            self.inner.show(ui, sync_writer, async_writer, state)
128        } else {
129            Ok(())
130        }
131    }
132
133    fn stop(
134        &mut self,
135        sync_writer: &mut QWriter<SyncSignal>,
136        async_writer: &mut QWriter<AsyncSignal>,
137        state: &State,
138    ) -> Result<Signal> {
139        if *self.wait_over.lock().unwrap() {
140            self.inner.stop(sync_writer, async_writer, state)
141        } else {
142            Ok(Signal::none())
143        }
144    }
145}