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
107#[cfg(test)]
108mod tests {
109 use std::cell::RefCell;
110
111 use super::*;
112 use crate::{Signal, all, next_frame, presets, sequence, spawn, wait_for, wait_until};
113
114 fn run<T>(fps: f64, fut: impl Future<Output = ()> + 'static, f: impl Fn() -> T) -> Vec<T> {
116 let mut ex = Executor::new(fps, Meta::default(), 0, fut);
117 let mut out = Vec::new();
118 for _ in 0..10_000 {
119 let done = ex.step();
120 out.push(f());
121 if done {
122 return out;
123 }
124 }
125 panic!("scene did not finish");
126 }
127
128 #[test]
129 fn tween_takes_exact_frames_and_hits_target() {
130 let s = Signal::new(0.0f64);
131 let s2 = s.clone();
132 let values = run(
133 60.0,
134 async move { s2.to(1.0, 1.0).ease(presets::LINEAR).await },
135 || s.get(),
136 );
137 assert_eq!(values.len(), 61);
139 assert_eq!(values[0], 0.0);
140 assert!((values[30] - 0.5).abs() < 1e-12);
141 assert_eq!(values[60], 1.0);
142 }
143
144 #[test]
145 fn chained_waits_do_not_drift() {
146 let frames = run(
148 24.0,
149 async {
150 for _ in 0..30 {
151 wait_for(0.1).await;
152 }
153 },
154 || (),
155 );
156 assert_eq!(frames.len(), 3 * 24 + 1);
157 }
158
159 #[test]
160 fn all_waits_for_longest_and_continues_from_its_end() {
161 let log = Rc::new(RefCell::new(Vec::new()));
162 let l = log.clone();
163 run(
164 10.0,
165 async move {
166 all((wait_for(0.5), wait_for(1.0), async {})).await;
167 l.borrow_mut().push((crate::frame(), crate::time()));
168 },
169 || (),
170 );
171 assert_eq!(*log.borrow(), vec![(10, 1.0)]);
172 }
173
174 #[test]
175 fn sequence_staggers_starts() {
176 let a = Signal::new(0.0f64);
177 let b = Signal::new(0.0f64);
178 let (a2, b2) = (a.clone(), b.clone());
179 let values = run(
180 10.0,
181 async move {
182 sequence(
183 0.5,
184 vec![
185 Box::pin(a2.to(1.0, 1.0).ease(presets::LINEAR)),
186 Box::pin(b2.to(1.0, 1.0).ease(presets::LINEAR)),
187 ],
188 )
189 .await;
190 },
191 || (a.get(), b.get()),
192 );
193 assert_eq!(values.len(), 16);
194 assert!((values[5].0 - 0.5).abs() < 1e-12);
195 assert_eq!(values[5].1, 0.0);
196 assert!((values[10].1 - 0.5).abs() < 1e-12);
197 }
198
199 #[test]
200 fn spawn_runs_in_background_and_join_waits() {
201 let s = Signal::new(0.0f64);
202 let s2 = s.clone();
203 let values = run(
204 10.0,
205 async move {
206 let h = spawn(async move { s2.to(1.0, 0.5).ease(presets::LINEAR).await });
207 next_frame().await;
208 h.await;
209 },
210 || s.get(),
211 );
212 assert!((values[2] - 0.4).abs() < 1e-12);
213 assert_eq!(*values.last().unwrap(), 1.0);
214 }
215
216 #[test]
217 fn wait_until_records_default_and_reads_meta() {
218 let mut ex = Executor::new(10.0, Meta::default(), 0, async {
219 wait_for(0.3).await;
220 wait_until("beat").await;
221 });
222 while !ex.step() {}
223 assert!((ex.meta().markers["beat"] - 0.3).abs() < 1e-12);
224 assert!(ex.take_meta_changed());
225
226 let mut meta = Meta::default();
227 meta.markers.insert("beat".into(), 1.0);
228 let mut ex = Executor::new(10.0, meta, 0, async {
229 wait_for(0.3).await;
230 wait_until("beat").await;
231 });
232 while !ex.step() {}
233 assert_eq!(ex.frames_done(), 11);
234 assert!(!ex.take_meta_changed());
235 }
236
237 #[test]
238 fn random_is_seeded() {
239 let draw = |seed| {
240 let out = Rc::new(RefCell::new(Vec::new()));
241 let o = out.clone();
242 let mut ex = Executor::new(10.0, Meta::default(), seed, async move {
243 for _ in 0..4 {
244 o.borrow_mut().push(crate::random());
245 }
246 });
247 ex.step();
248 out.take()
249 };
250 assert_eq!(draw(1), draw(1));
251 assert_ne!(draw(1), draw(2));
252 assert!(draw(3).iter().all(|v| (0.0..1.0).contains(v)));
253 }
254}