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