|
| 1 | +use std::{future::Future, marker::PhantomData}; |
| 2 | + |
| 3 | +/// Provides Future extension methods useful for writing UI. |
| 4 | +/// |
| 5 | +/// Implemented for every `Future` type. |
| 6 | +pub trait UiFutureExt: Future + Sized { |
| 7 | + /// Turn the given future into one that never finishes. |
| 8 | + /// |
| 9 | + /// You can specify the output type of the output future to be anything, |
| 10 | + /// because the future will never produce output. |
| 11 | + /// |
| 12 | + /// ```rust |
| 13 | + /// # async fn my_async_fn() {} |
| 14 | + /// use async_ui_web_core::combinators::UiFutureExt; |
| 15 | + /// let fut = my_async_fn().pend_after::<std::convert::Infallible>(); |
| 16 | + /// fut.await; // will never finish |
| 17 | + /// ``` |
| 18 | + /// |
| 19 | + /// `f.pend_after()` is equivalent to |
| 20 | + /// ```rust |
| 21 | + /// # let f = async {}; |
| 22 | + /// async { |
| 23 | + /// f.await; |
| 24 | + /// std::future::pending() |
| 25 | + /// } |
| 26 | + /// ``` |
| 27 | + fn pend_after<T>(self) -> PendAfter<Self, T> { |
| 28 | + PendAfter { |
| 29 | + future: Some(self), |
| 30 | + _phantom: PhantomData, |
| 31 | + } |
| 32 | + } |
| 33 | + /// Run some Future while this one is running. |
| 34 | + /// |
| 35 | + /// `f.meanwhile(g)` is equivalent to |
| 36 | + /// ```rust |
| 37 | + /// # let (f, g) = (async {}, async{}); |
| 38 | + /// # use async_ui_web_core::combinators::{UiFutureExt, race}; |
| 39 | + /// race(( |
| 40 | + /// f, |
| 41 | + /// g.pend_after() |
| 42 | + /// )) |
| 43 | + /// ``` |
| 44 | + fn meanwhile<F: Future>( |
| 45 | + self, |
| 46 | + effect: F, |
| 47 | + ) -> <(Self, PendAfter<F, Self::Output>) as super::race::Race>::Future { |
| 48 | + use super::race::Race; |
| 49 | + (self, effect.pend_after()).race() |
| 50 | + } |
| 51 | +} |
| 52 | + |
| 53 | +impl<F: Future> UiFutureExt for F {} |
| 54 | + |
| 55 | +#[pin_project::pin_project] |
| 56 | +pub struct PendAfter<F: Future, T> { |
| 57 | + #[pin] |
| 58 | + future: Option<F>, |
| 59 | + _phantom: PhantomData<T>, |
| 60 | +} |
| 61 | + |
| 62 | +impl<F: Future, T> Future for PendAfter<F, T> { |
| 63 | + type Output = T; |
| 64 | + |
| 65 | + fn poll( |
| 66 | + self: std::pin::Pin<&mut Self>, |
| 67 | + cx: &mut std::task::Context<'_>, |
| 68 | + ) -> std::task::Poll<Self::Output> { |
| 69 | + let mut this = self.project(); |
| 70 | + if let Some(fut) = this.future.as_mut().as_pin_mut() { |
| 71 | + if fut.poll(cx).is_ready() { |
| 72 | + this.future.set(None); |
| 73 | + } |
| 74 | + } |
| 75 | + std::task::Poll::Pending |
| 76 | + } |
| 77 | +} |
0 commit comments