1use pin_project_lite::pin_project;
2
3use super::{task, Future, Pin, Poll};
4
5pub(crate) trait Started: Future {
6 fn started(&self) -> bool;
7}
8
9pub(crate) fn lazy<F, R>(func: F) -> Lazy<F, R>
10where
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
20pin_project! {
21 #[allow(missing_debug_implementations)]
22 pub(crate) struct Lazy<F, R> {
23 #[pin]
24 inner: Inner<F, R>,
25 }
26}
27
28pin_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
38impl<F, R> Started for Lazy<F, R>
39where
40 F: FnOnce() -> R,
41 R: Future,
42{
43 fn started(&self) -> bool {
44 match self.inner {
45 Inner::Init { .. } => false,
46 Inner::Fut { .. } | Inner::Empty => true,
47 }
48 }
49}
50
51impl<F, R> Future for Lazy<F, R>
52where
53 F: FnOnce() -> R,
54 R: Future,
55{
56 type Output = R::Output;
57
58 fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
59 let mut this: Projection<'_, F, R> = self.project();
60
61 if let InnerProj::Fut { fut: Pin<&mut R> } = this.inner.as_mut().project() {
62 return fut.poll(cx);
63 }
64
65 match this.inner.as_mut().project_replace(replacement:Inner::Empty) {
66 InnerProjReplace::Init { func: F } => {
67 this.inner.set(Inner::Fut { fut: func() });
68 if let InnerProj::Fut { fut: Pin<&mut R> } = this.inner.project() {
69 return fut.poll(cx);
70 }
71 unreachable!()
72 }
73 _ => unreachable!("lazy state wrong"),
74 }
75 }
76}
77