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