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