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