1use std::future::Future;
2use std::rc::Rc;
3use std::task::{Context, Waker};
4
5use oxframe_protocol::Meta;
6
7use crate::flow::{Task, TaskState};
8use crate::runtime::{self, Runtime};
9
10pub struct Executor {
15 rt: Rc<Runtime>,
16 root: Option<Task>,
17 tasks: Vec<Task>,
18 next_frame: u32,
19}
20
21impl Executor {
22 pub fn new(fps: f64, meta: Meta, seed: u64, root: impl Future<Output = ()> + 'static) -> Self {
24 Self {
25 rt: Runtime::new(fps, meta, seed),
26 root: Some(Task {
27 fut: Box::pin(root),
28 time: 0.0,
29 state: Rc::new(TaskState {
30 finished: Default::default(),
31 cancelled: Default::default(),
32 }),
33 }),
34 tasks: Vec::new(),
35 next_frame: 0,
36 }
37 }
38
39 pub fn enter<R>(&self, f: impl FnOnce() -> R) -> R {
42 let _guard = runtime::install(&self.rt);
43 f()
44 }
45
46 pub fn step(&mut self) -> bool {
49 let Some(root) = self.root.as_mut() else {
50 return true;
51 };
52 let _guard = runtime::install(&self.rt);
53 self.rt.frame.set(self.next_frame);
54 let mut cx = Context::from_waker(Waker::noop());
55
56 let root_done = root.poll(&mut cx);
57 self.tasks.retain_mut(|t| !t.poll(&mut cx));
58 loop {
60 let new: Vec<Task> = std::mem::take(&mut *self.rt.spawned.borrow_mut());
61 if new.is_empty() {
62 break;
63 }
64 for mut t in new {
65 if !t.poll(&mut cx) {
66 self.tasks.push(t);
67 }
68 }
69 }
70
71 self.next_frame += 1;
72 if root_done {
73 self.root = None;
74 self.tasks.clear();
75 }
76 root_done
77 }
78
79 pub fn is_finished(&self) -> bool {
81 self.root.is_none()
82 }
83
84 pub fn frames_done(&self) -> u32 {
87 self.next_frame
88 }
89
90 pub fn fps(&self) -> f64 {
92 self.rt.fps
93 }
94
95 pub fn meta(&self) -> Meta {
97 self.rt.meta.borrow().clone()
98 }
99
100 pub fn take_meta_changed(&self) -> bool {
103 self.rt.meta_changed.replace(false)
104 }
105
106 pub fn set_has_previous(&self, has_previous: bool) {
108 self.rt.has_previous.set(has_previous);
109 }
110
111 pub fn transition(&self) -> Option<crate::transition::Recorded> {
113 *self.rt.transition.borrow()
114 }
115
116 pub fn sounds(&self) -> Vec<crate::SoundClip> {
118 self.rt.sounds.borrow().clone()
119 }
120
121 pub fn voices(&self) -> Vec<crate::VoiceLine> {
123 self.rt.voices.borrow().clone()
124 }
125
126 pub fn slides(&self) -> Vec<crate::SlideMark> {
128 self.rt.slides.borrow().clone()
129 }
130}
131
132#[cfg(test)]
133mod tests {
134 use std::cell::RefCell;
135
136 use super::*;
137 use crate::{
138 Signal, all, any, loop_while, next_frame, presets, repeat, sequence, spawn, stagger,
139 wait_for, wait_until,
140 };
141
142 fn run<T>(fps: f64, fut: impl Future<Output = ()> + 'static, f: impl Fn() -> T) -> Vec<T> {
144 let mut ex = Executor::new(fps, Meta::default(), 0, fut);
145 let mut out = Vec::new();
146 for _ in 0..10_000 {
147 let done = ex.step();
148 out.push(f());
149 if done {
150 return out;
151 }
152 }
153 panic!("scene did not finish");
154 }
155
156 #[test]
157 fn tween_takes_exact_frames_and_hits_target() {
158 let s = Signal::new(0.0f64);
159 let s2 = s.clone();
160 let values = run(
161 60.0,
162 async move { s2.to(1.0, 1.0).ease(presets::LINEAR).await },
163 || s.get(),
164 );
165 assert_eq!(values.len(), 61);
167 assert_eq!(values[0], 0.0);
168 assert!((values[30] - 0.5).abs() < 1e-12);
169 assert_eq!(values[60], 1.0);
170 }
171
172 #[test]
173 fn chained_waits_do_not_drift() {
174 let frames = run(
176 24.0,
177 async {
178 for _ in 0..30 {
179 wait_for(0.1).await;
180 }
181 },
182 || (),
183 );
184 assert_eq!(frames.len(), 3 * 24 + 1);
185 }
186
187 #[test]
188 fn all_waits_for_longest_and_continues_from_its_end() {
189 let log = Rc::new(RefCell::new(Vec::new()));
190 let l = log.clone();
191 run(
192 10.0,
193 async move {
194 all((wait_for(0.5), wait_for(1.0), async {})).await;
195 l.borrow_mut().push((crate::frame(), crate::time()));
196 },
197 || (),
198 );
199 assert_eq!(*log.borrow(), vec![(10, 1.0)]);
200 }
201
202 #[test]
203 fn sequence_staggers_starts() {
204 let a = Signal::new(0.0f64);
205 let b = Signal::new(0.0f64);
206 let (a2, b2) = (a.clone(), b.clone());
207 let values = run(
208 10.0,
209 async move {
210 sequence(
211 0.5,
212 [
213 a2.to(1.0, 1.0).ease(presets::LINEAR),
214 b2.to(1.0, 1.0).ease(presets::LINEAR),
215 ],
216 )
217 .await;
218 },
219 || (a.get(), b.get()),
220 );
221 assert_eq!(values.len(), 16);
222 assert!((values[5].0 - 0.5).abs() < 1e-12);
223 assert_eq!(values[5].1, 0.0);
224 assert!((values[10].1 - 0.5).abs() < 1e-12);
225 }
226
227 #[test]
228 fn spawn_runs_in_background_and_join_waits() {
229 let s = Signal::new(0.0f64);
230 let s2 = s.clone();
231 let values = run(
232 10.0,
233 async move {
234 let h = spawn(async move { s2.to(1.0, 0.5).ease(presets::LINEAR).await });
235 next_frame().await;
236 h.await;
237 },
238 || s.get(),
239 );
240 assert!((values[2] - 0.4).abs() < 1e-12);
241 assert_eq!(*values.last().unwrap(), 1.0);
242 }
243
244 #[test]
245 fn wait_until_records_default_and_reads_meta() {
246 let mut ex = Executor::new(10.0, Meta::default(), 0, async {
247 wait_for(0.3).await;
248 wait_until("beat").await;
249 });
250 while !ex.step() {}
251 assert!((ex.meta().markers["beat"] - 0.3).abs() < 1e-12);
252 assert!(ex.take_meta_changed());
253
254 let mut meta = Meta::default();
255 meta.markers.insert("beat".into(), 1.0);
256 let mut ex = Executor::new(10.0, meta, 0, async {
257 wait_for(0.3).await;
258 wait_until("beat").await;
259 });
260 while !ex.step() {}
261 assert_eq!(ex.frames_done(), 11);
262 assert!(!ex.take_meta_changed());
263 }
264
265 #[test]
266 fn random_is_seeded() {
267 let draw = |seed| {
268 let out = Rc::new(RefCell::new(Vec::new()));
269 let o = out.clone();
270 let mut ex = Executor::new(10.0, Meta::default(), seed, async move {
271 for _ in 0..4 {
272 o.borrow_mut().push(crate::random());
273 }
274 });
275 ex.step();
276 out.take()
277 };
278 assert_eq!(draw(1), draw(1));
279 assert_ne!(draw(1), draw(2));
280 assert!(draw(3).iter().all(|v| (0.0..1.0).contains(v)));
281 }
282
283 fn end_of(fps: f64, fut: impl Future<Output = ()> + 'static) -> (u32, f64) {
285 let log = Rc::new(RefCell::new(None));
286 let l = log.clone();
287 run(
288 fps,
289 async move {
290 fut.await;
291 *l.borrow_mut() = Some((crate::frame(), crate::time()));
292 },
293 || (),
294 );
295 log.borrow().expect("logged")
296 }
297
298 #[test]
299 fn all_takes_vecs_arrays_and_iterators() {
300 let durations = [0.5, 1.0, 0.2];
301 assert_eq!(
302 end_of(10.0, async move {
303 all(durations.map(wait_for)).await;
304 })
305 .1,
306 1.0
307 );
308 assert_eq!(
309 end_of(10.0, async move {
310 all(durations.iter().map(|&d| wait_for(d))).await;
311 })
312 .1,
313 1.0
314 );
315 assert_eq!(
316 end_of(10.0, async move {
317 all(vec![wait_for(0.3), wait_for(0.7)]).await;
318 })
319 .1,
320 0.7
321 );
322 let out = Rc::new(RefCell::new(Vec::new()));
324 let o = out.clone();
325 end_of(10.0, async move {
326 *o.borrow_mut() = all((1..=3).map(|i| async move { i * 10 })).await;
327 });
328 assert_eq!(*out.borrow(), vec![10, 20, 30]);
329 assert_eq!(
331 end_of(10.0, async {
332 all(Vec::<crate::flow::WaitFor>::new()).await;
333 })
334 .1,
335 0.0
336 );
337 }
338
339 #[test]
340 fn any_completes_with_the_first_and_continues_from_its_end() {
341 let s = Signal::new(0.0f64);
342 let s2 = s.clone();
343 let first = Rc::new(RefCell::new(None));
344 let f = first.clone();
345 let (frame, time) = end_of(10.0, async move {
346 let i = any((
347 wait_for(2.0),
348 s2.to(1.0, 2.0).ease(presets::LINEAR),
349 wait_for(0.5),
350 ))
351 .await;
352 *f.borrow_mut() = Some(i);
353 });
354 assert_eq!(*first.borrow(), Some(2));
355 assert_eq!((frame, time), (5, 0.5));
356 assert!((s.get() - 0.25).abs() < 1e-12, "{}", s.get());
358 }
359
360 #[test]
361 fn stagger_starts_each_item_later() {
362 let signals: Vec<Signal<f64>> = (0..3).map(|_| Signal::new(0.0)).collect();
363 let watch = signals.clone();
364 let values = run(
365 10.0,
366 async move {
367 stagger(0.2, &signals, |s| s.to(1.0, 1.0).ease(presets::LINEAR)).await;
368 },
369 move || watch.iter().map(Signal::get).collect::<Vec<_>>(),
370 );
371 assert_eq!(values.len(), 15);
373 let at_half = &values[5];
374 assert!((at_half[0] - 0.5).abs() < 1e-12);
375 assert!((at_half[1] - 0.3).abs() < 1e-12);
376 assert!((at_half[2] - 0.1).abs() < 1e-12);
377 }
378
379 #[test]
380 fn repeat_and_loop_while() {
381 assert_eq!(end_of(10.0, repeat(3, || wait_for(0.5))).1, 1.5);
382 let left = Rc::new(std::cell::Cell::new(4));
383 let l = left.clone();
384 let end = end_of(
385 10.0,
386 loop_while(
387 move || {
388 l.set(l.get() - 1);
389 l.get() >= 0
390 },
391 || wait_for(0.25),
392 ),
393 );
394 assert_eq!(end.1, 1.0);
395 assert_eq!(left.get(), -1);
396 }
397}