Skip to main content

oxframe_core/
flow.rs

1use std::cell::Cell;
2use std::future::Future;
3use std::pin::Pin;
4use std::rc::Rc;
5use std::task::{Context, Poll};
6
7use crate::runtime;
8use crate::tween::progress;
9
10/// A boxed scene future, e.g. for [`sequence`].
11pub type BoxFuture<T = ()> = Pin<Box<dyn Future<Output = T>>>;
12
13/// Polls `fut` with its own virtual time and writes the time back.
14fn poll_scoped<F: Future + ?Sized>(
15    fut: Pin<&mut F>,
16    time: &mut f64,
17    cx: &mut Context<'_>,
18) -> Poll<F::Output> {
19    runtime::with(|rt| {
20        let outer = rt.task_time.replace(*time);
21        // `with` holds only a shared borrow of the thread-local, so nested
22        // runtime calls from inside the poll are fine.
23        let r = fut.poll(cx);
24        *time = rt.task_time.replace(outer);
25        r
26    })
27}
28
29// ---------------------------------------------------------------- timers
30
31/// Waits `seconds` of scene time.
32pub fn wait_for(seconds: f64) -> WaitFor {
33    WaitFor {
34        duration: seconds.max(0.0),
35        start: None,
36    }
37}
38
39/// A wait returned by [`wait_for`].
40#[must_use = "futures do nothing unless awaited"]
41pub struct WaitFor {
42    duration: f64,
43    start: Option<f64>,
44}
45
46impl Future for WaitFor {
47    type Output = ();
48
49    fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<()> {
50        let start = *self.start.get_or_insert_with(runtime::time);
51        match progress(start, self.duration) {
52            None => Poll::Ready(()),
53            Some(_) => Poll::Pending,
54        }
55    }
56}
57
58/// Waits until marker `name` from `meta.json`. On first encounter the
59/// current time becomes the marker's default, so it does not wait at all.
60pub fn wait_until(name: &str) -> WaitUntil {
61    WaitUntil {
62        name: name.to_owned(),
63        inner: None,
64    }
65}
66
67#[must_use = "futures do nothing unless awaited"]
68pub struct WaitUntil {
69    name: String,
70    inner: Option<WaitFor>,
71}
72
73impl Future for WaitUntil {
74    type Output = ();
75
76    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
77        let this = &mut *self;
78        let inner = this.inner.get_or_insert_with(|| {
79            let target = runtime::marker(&this.name);
80            wait_for(target - runtime::time())
81        });
82        Pin::new(inner).poll(cx)
83    }
84}
85
86/// Yields until the next frame.
87pub fn next_frame() -> NextFrame {
88    NextFrame { frame: None }
89}
90
91#[must_use = "futures do nothing unless awaited"]
92pub struct NextFrame {
93    frame: Option<u32>,
94}
95
96impl Future for NextFrame {
97    type Output = ();
98
99    fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<()> {
100        let current = runtime::frame();
101        let first = *self.frame.get_or_insert(current);
102        if current > first {
103            runtime::with(|rt| rt.task_time.set(rt.task_time.get().max(rt.now())));
104            Poll::Ready(())
105        } else {
106            Poll::Pending
107        }
108    }
109}
110
111// ---------------------------------------------------------------- all
112
113/// One branch of [`all`]: a future with its own virtual time.
114pub struct Branch<F: Future> {
115    fut: Option<Pin<Box<F>>>,
116    out: Option<F::Output>,
117    time: f64,
118}
119
120impl<F: Future> Branch<F> {
121    fn new(fut: F) -> Self {
122        Self {
123            fut: Some(Box::pin(fut)),
124            out: None,
125            time: f64::NAN,
126        }
127    }
128
129    /// Returns true when finished.
130    fn poll(&mut self, start: f64, cx: &mut Context<'_>) -> bool {
131        if self.time.is_nan() {
132            self.time = start;
133        }
134        if let Some(fut) = self.fut.as_mut()
135            && let Poll::Ready(v) = poll_scoped(fut.as_mut(), &mut self.time, cx)
136        {
137            self.out = Some(v);
138            self.fut = None;
139        }
140        self.fut.is_none()
141    }
142
143    fn take(&mut self) -> F::Output {
144        self.out.take().expect("branch output taken twice")
145    }
146}
147
148/// Runs animations at the same time and completes when all of them have.
149///
150/// Takes a tuple of up to 12 futures of any types (`all((a, b, c))`), or any
151/// number of futures of one type: a `Vec`, an array or an iterator, e.g.
152/// `all(cards.iter().map(|c| c.fade_in()))`. Returns their outputs (a tuple
153/// or a `Vec`).
154///
155/// Every branch starts at the same time; afterwards the task continues from
156/// the latest end time among them.
157pub fn all<T: IntoAll>(futures: T) -> All<T::Branches> {
158    All {
159        branches: futures.into_branches(),
160        start: None,
161    }
162}
163
164/// Runs animations at the same time and completes as soon as the first one
165/// does; the others stop where they are. Returns the index of the one that
166/// finished. Takes the same arguments as [`all`].
167pub fn any<T: IntoAll>(futures: T) -> Any<T::Branches> {
168    Any {
169        branches: futures.into_branches(),
170        start: None,
171    }
172}
173
174#[must_use = "futures do nothing unless awaited"]
175/// Future returned by [`all`].
176pub struct All<B> {
177    branches: B,
178    start: Option<f64>,
179}
180
181#[must_use = "futures do nothing unless awaited"]
182/// Future returned by [`any`].
183pub struct Any<B> {
184    branches: B,
185    start: Option<f64>,
186}
187
188/// What [`all`] and [`any`] accept: a tuple of futures, or a `Vec`, array or
189/// iterator of futures of one type.
190#[diagnostic::on_unimplemented(
191    message = "`all`/`any` cannot run `{Self}` concurrently",
192    label = "expected a tuple, Vec, array or iterator of animations",
193    note = "write `all((a, b))` with double parentheses for a few animations, or \
194            `all(items.iter().map(|x| x.fade_in()))` for many of the same kind",
195    note = "did you forget to call the animation, e.g. `x.fade_in()` instead of `x.fade_in`?"
196)]
197pub trait IntoAll {
198    /// The branches being polled.
199    type Branches: Branches;
200    /// Wraps every future in a branch.
201    fn into_branches(self) -> Self::Branches;
202}
203
204/// Branches run by [`all`] and [`any`]. Implemented by the crate only.
205pub trait Branches: sealed::Sealed {
206    /// Outputs of all branches.
207    type Output;
208    /// Polls unfinished branches; returns the max end time once all are done.
209    fn poll_all(&mut self, start: f64, cx: &mut Context<'_>) -> Option<f64>;
210    /// Polls all branches; returns `(index, end time)` of the first finished.
211    fn poll_any(&mut self, start: f64, cx: &mut Context<'_>) -> Option<(usize, f64)>;
212    /// Outputs, once all are done.
213    fn take(&mut self) -> Self::Output;
214}
215
216mod sealed {
217    pub trait Sealed {}
218    impl<F: std::future::Future> Sealed for super::VecBranches<F> {}
219}
220
221impl<B: Branches + Unpin> Future for All<B> {
222    type Output = B::Output;
223
224    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<B::Output> {
225        let this = &mut *self;
226        let start = *this.start.get_or_insert_with(runtime::time);
227        match this.branches.poll_all(start, cx) {
228            Some(end) => {
229                runtime::with(|rt| rt.task_time.set(end));
230                Poll::Ready(this.branches.take())
231            }
232            None => Poll::Pending,
233        }
234    }
235}
236
237impl<B: Branches + Unpin> Future for Any<B> {
238    type Output = usize;
239
240    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<usize> {
241        let this = &mut *self;
242        let start = *this.start.get_or_insert_with(runtime::time);
243        match this.branches.poll_any(start, cx) {
244            Some((index, end)) => {
245                runtime::with(|rt| rt.task_time.set(end));
246                Poll::Ready(index)
247            }
248            None => Poll::Pending,
249        }
250    }
251}
252
253macro_rules! impl_all {
254    ($($F:ident $i:tt),+) => {
255        impl<$($F: Future),+> IntoAll for ($($F,)+) {
256            type Branches = ($(Branch<$F>,)+);
257            fn into_branches(self) -> Self::Branches {
258                ($(Branch::new(self.$i),)+)
259            }
260        }
261
262        impl<$($F: Future),+> sealed::Sealed for ($(Branch<$F>,)+) {}
263
264        impl<$($F: Future),+> Branches for ($(Branch<$F>,)+) {
265            type Output = ($($F::Output,)+);
266
267            fn poll_all(&mut self, start: f64, cx: &mut Context<'_>) -> Option<f64> {
268                let mut done = true;
269                $( done &= self.$i.poll(start, cx); )+
270                done.then(|| {
271                    let mut end = start;
272                    $( end = end.max(self.$i.time); )+
273                    end
274                })
275            }
276
277            fn poll_any(&mut self, start: f64, cx: &mut Context<'_>) -> Option<(usize, f64)> {
278                let mut first: Option<(usize, f64)> = None;
279                $(
280                    if self.$i.poll(start, cx) && first.is_none() {
281                        first = Some(($i, self.$i.time));
282                    }
283                )+
284                first
285            }
286
287            fn take(&mut self) -> Self::Output {
288                ($(self.$i.take(),)+)
289            }
290        }
291    };
292}
293
294impl_all!(A 0);
295impl_all!(A 0, B 1);
296impl_all!(A 0, B 1, C 2);
297impl_all!(A 0, B 1, C 2, D 3);
298impl_all!(A 0, B 1, C 2, D 3, E 4);
299impl_all!(A 0, B 1, C 2, D 3, E 4, F 5);
300impl_all!(A 0, B 1, C 2, D 3, E 4, F 5, G 6);
301impl_all!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7);
302impl_all!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8);
303impl_all!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9);
304impl_all!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9, K 10);
305impl_all!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9, K 10, L 11);
306
307impl<F: Future> IntoAll for Vec<F> {
308    type Branches = VecBranches<F>;
309    fn into_branches(self) -> VecBranches<F> {
310        VecBranches(self.into_iter().map(Branch::new).collect())
311    }
312}
313
314impl<F: Future, const N: usize> IntoAll for [F; N] {
315    type Branches = VecBranches<F>;
316    fn into_branches(self) -> VecBranches<F> {
317        VecBranches(self.into_iter().map(Branch::new).collect())
318    }
319}
320
321/// `items.iter().map(|x| animation)`: the common way to animate many nodes.
322impl<I: Iterator, G: FnMut(I::Item) -> F, F: Future> IntoAll for std::iter::Map<I, G> {
323    type Branches = VecBranches<F>;
324    fn into_branches(self) -> VecBranches<F> {
325        VecBranches(self.map(Branch::new).collect())
326    }
327}
328
329/// Branches of [`all`] or [`any`] over many futures of one type.
330pub struct VecBranches<F: Future>(Vec<Branch<F>>);
331
332impl<F: Future> Branches for VecBranches<F> {
333    type Output = Vec<F::Output>;
334
335    fn poll_all(&mut self, start: f64, cx: &mut Context<'_>) -> Option<f64> {
336        let mut done = true;
337        for b in &mut self.0 {
338            done &= b.poll(start, cx);
339        }
340        done.then(|| self.0.iter().fold(start, |end, b| end.max(b.time)))
341    }
342
343    fn poll_any(&mut self, start: f64, cx: &mut Context<'_>) -> Option<(usize, f64)> {
344        if self.0.is_empty() {
345            return Some((0, start));
346        }
347        let mut first = None;
348        for (i, b) in self.0.iter_mut().enumerate() {
349            if b.poll(start, cx) && first.is_none() {
350                first = Some((i, b.time));
351            }
352        }
353        first
354    }
355
356    fn take(&mut self) -> Vec<F::Output> {
357        self.0.iter_mut().map(Branch::take).collect()
358    }
359}
360
361/// Anything that can be awaited in a scene: a tween, `wait_for`, `all(..)`,
362/// an `async` block… Every future is one; the trait exists for the error
363/// message when a closure returns something else.
364#[diagnostic::on_unimplemented(
365    message = "`{Self}` is not an animation",
366    label = "expected an animation such as `x.fade_in()` or `x.x().to(100.0, 1.0)`",
367    note = "a closure body ending in `;` returns `()`: drop the `;`, or write \
368            `async move {{ a.await; b.await; }}` for several steps"
369)]
370pub trait Animation: Future {}
371
372impl<F: Future> Animation for F {}
373
374/// [`all`] for boxed futures.
375#[deprecated(since = "0.3.0", note = "`all` takes a Vec now: `all(futures)`")]
376pub fn all_vec<T: 'static>(futures: Vec<BoxFuture<T>>) -> All<VecBranches<BoxFuture<T>>> {
377    all(futures)
378}
379
380/// Starts animations one after another, `delay` seconds apart; they then run
381/// concurrently. Completes when all have. Takes a `Vec`, an array or an
382/// iterator of animations of one type. For "the same animation on many
383/// nodes", [`stagger`] reads better.
384pub fn sequence<I>(delay: f64, futures: I) -> All<VecBranches<Delayed<I::Item>>>
385where
386    I: IntoIterator,
387    I::Item: Animation,
388{
389    all(futures
390        .into_iter()
391        .enumerate()
392        .map(|(i, fut)| Delayed {
393            wait: wait_for(delay * i as f64),
394            waited: false,
395            fut: Box::pin(fut),
396        })
397        .collect::<Vec<_>>())
398}
399
400/// Runs `animate` on every item, starting each `delay` seconds after the
401/// previous one; completes when all have finished:
402///
403/// ```ignore
404/// stagger(0.15, &cards, |c| c.fade_in()).await;
405/// ```
406pub fn stagger<I, F>(
407    delay: f64,
408    items: I,
409    animate: impl FnMut(I::Item) -> F,
410) -> All<VecBranches<Delayed<F>>>
411where
412    I: IntoIterator,
413    F: Animation,
414{
415    sequence(delay, items.into_iter().map(animate))
416}
417
418/// A future that starts after a wait; see [`sequence`].
419#[must_use = "futures do nothing unless awaited"]
420pub struct Delayed<F: Future> {
421    wait: WaitFor,
422    waited: bool,
423    fut: Pin<Box<F>>,
424}
425
426impl<F: Future> Future for Delayed<F> {
427    type Output = F::Output;
428
429    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<F::Output> {
430        let this = &mut *self;
431        if !this.waited {
432            if Pin::new(&mut this.wait).poll(cx).is_pending() {
433                return Poll::Pending;
434            }
435            this.waited = true;
436        }
437        this.fut.as_mut().poll(cx)
438    }
439}
440
441/// Runs the animation `make()` returns `times` times in a row.
442pub async fn repeat<F: Animation>(times: usize, mut make: impl FnMut() -> F) {
443    for _ in 0..times {
444        make().await;
445    }
446}
447
448/// Runs the animation `make()` returns again and again while `keep_going()`
449/// is true (checked before each run). Usually `spawn`ed for a background
450/// loop: `spawn(loop_while(|| true, || pulse.scale().to(1.1, 0.5)))`.
451pub async fn loop_while<F: Animation>(
452    mut keep_going: impl FnMut() -> bool,
453    mut make: impl FnMut() -> F,
454) {
455    while keep_going() {
456        make().await;
457    }
458}
459
460// ---------------------------------------------------------------- spawn
461
462pub(crate) struct TaskState {
463    pub finished: Cell<bool>,
464    pub cancelled: Cell<bool>,
465}
466
467pub(crate) struct Task {
468    pub fut: BoxFuture,
469    pub time: f64,
470    pub state: Rc<TaskState>,
471}
472
473impl Task {
474    /// Returns true when the task is done (finished or cancelled).
475    pub fn poll(&mut self, cx: &mut Context<'_>) -> bool {
476        if self.state.cancelled.get() {
477            return true;
478        }
479        if poll_scoped(self.fut.as_mut(), &mut self.time, cx).is_ready() {
480            self.state.finished.set(true);
481        }
482        self.state.finished.get()
483    }
484}
485
486/// Runs `fut` in the background, starting this frame. Background tasks stop
487/// when the scene ends.
488pub fn spawn(fut: impl Future<Output = ()> + 'static) -> JoinHandle {
489    let state = Rc::new(TaskState {
490        finished: Cell::new(false),
491        cancelled: Cell::new(false),
492    });
493    runtime::with(|rt| {
494        rt.spawned.borrow_mut().push(Task {
495            fut: Box::pin(fut),
496            time: rt.task_time.get(),
497            state: state.clone(),
498        });
499    });
500    JoinHandle { state }
501}
502
503/// Awaiting it waits for the spawned task to finish.
504pub struct JoinHandle {
505    state: Rc<TaskState>,
506}
507
508impl JoinHandle {
509    /// Whether the task has completed or was cancelled.
510    pub fn is_finished(&self) -> bool {
511        self.state.finished.get()
512    }
513
514    /// Stops the task at its next await point.
515    pub fn cancel(&self) {
516        self.state.cancelled.set(true);
517    }
518}
519
520impl Future for JoinHandle {
521    type Output = ();
522
523    fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<()> {
524        if self.state.finished.get() || self.state.cancelled.get() {
525            Poll::Ready(())
526        } else {
527            Poll::Pending
528        }
529    }
530}