1 use pin_project_lite::pin_project;
2 
3 use super::{task, Future, Pin, Poll};
4 
5 pub(crate) trait Started: Future {
started(&self) -> bool6     fn started(&self) -> bool;
7 }
8 
lazy<F, R>(func: F) -> Lazy<F, R> where F: FnOnce() -> R, R: Future + Unpin,9 pub(crate) fn lazy<F, R>(func: F) -> Lazy<F, R>
10 where
11     F: FnOnce() -> R,
12     R: Future + Unpin,
13 {
14     Lazy {
15         inner: Inner::Init { func },
16     }
17 }
18 
19 // FIXME: allow() required due to `impl Trait` leaking types to this lint
20 pin_project! {
21     #[allow(missing_debug_implementations)]
22     pub(crate) struct Lazy<F, R> {
23         #[pin]
24         inner: Inner<F, R>,
25     }
26 }
27 
28 pin_project! {
29     #[project = InnerProj]
30     #[project_replace = InnerProjReplace]
31     enum Inner<F, R> {
32         Init { func: F },
33         Fut { #[pin] fut: R },
34         Empty,
35     }
36 }
37 
38 impl<F, R> Started for Lazy<F, R>
39 where
40     F: FnOnce() -> R,
41     R: Future,
42 {
started(&self) -> bool43     fn started(&self) -> bool {
44         match self.inner {
45             Inner::Init { .. } => false,
46             Inner::Fut { .. } | Inner::Empty => true,
47         }
48     }
49 }
50 
51 impl<F, R> Future for Lazy<F, R>
52 where
53     F: FnOnce() -> R,
54     R: Future,
55 {
56     type Output = R::Output;
57 
poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output>58     fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
59         let mut this = self.project();
60 
61         if let InnerProj::Fut { fut } = this.inner.as_mut().project() {
62             return fut.poll(cx);
63         }
64 
65         match this.inner.as_mut().project_replace(Inner::Empty) {
66             InnerProjReplace::Init { func } => {
67                 this.inner.set(Inner::Fut { fut: func() });
68                 if let InnerProj::Fut { fut } = this.inner.project() {
69                     return fut.poll(cx);
70                 }
71                 unreachable!()
72             }
73             _ => unreachable!("lazy state wrong"),
74         }
75     }
76 }
77