aws_smithy_async/future/
now_or_later.rs1use std::fmt;
52use std::future::Future;
53use std::pin::Pin;
54use std::task::{Context, Poll};
55
56use pin_project_lite::pin_project;
57
58pub type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
60
61#[derive(Debug)]
62pub enum OnlyReady {}
64
65pin_project! {
66    pub struct NowOrLater<T, F> {
70        #[pin]
71        inner: Inner<T, F>
72    }
73}
74
75impl<T, F> fmt::Debug for NowOrLater<T, F>
76where
77    T: fmt::Debug,
78{
79    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80        f.debug_struct("NowOrLater")
81            .field("inner", &self.inner)
82            .finish()
83    }
84}
85
86pin_project! {
87    #[project = NowOrLaterProj]
88    enum Inner<T, F> {
89        #[non_exhaustive]
90        Now { value: Option<T> },
91        #[non_exhaustive]
92        Later { #[pin] future: F },
93    }
94}
95
96impl<T, F> fmt::Debug for Inner<T, F>
97where
98    T: fmt::Debug,
99{
100    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101        match self {
102            Self::Now { value } => f.debug_struct("Now").field("value", value).finish(),
103            Self::Later { .. } => f
104                .debug_struct("Later")
105                .field("future", &"<future>")
106                .finish(),
107        }
108    }
109}
110
111impl<T, F> NowOrLater<T, F> {
112    pub fn new(future: F) -> Self {
114        Self {
115            inner: Inner::Later { future },
116        }
117    }
118
119    pub fn ready(value: T) -> NowOrLater<T, F> {
121        let value = Some(value);
122        Self {
123            inner: Inner::Now { value },
124        }
125    }
126}
127
128impl<T, F> Future for NowOrLater<T, F>
129where
130    F: Future<Output = T>,
131{
132    type Output = T;
133
134    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
135        match self.project().inner.project() {
136            NowOrLaterProj::Now { value } => {
137                Poll::Ready(value.take().expect("cannot be called twice"))
138            }
139            NowOrLaterProj::Later { future } => future.poll(cx),
140        }
141    }
142}
143
144impl<T> Future for NowOrLater<T, OnlyReady> {
145    type Output = T;
146
147    fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
148        match self.project().inner.project() {
149            NowOrLaterProj::Now { value } => {
150                Poll::Ready(value.take().expect("cannot be called twice"))
151            }
152            NowOrLaterProj::Later { .. } => unreachable!(),
153        }
154    }
155}
156
157#[cfg(test)]
158mod test {
159    use crate::future::now_or_later::{NowOrLater, OnlyReady};
160    use futures_util::FutureExt;
161
162    #[test]
163    fn ready_future_immediately_returns() {
164        let a = true;
165        let f = if a {
166            NowOrLater::ready(5)
167        } else {
168            NowOrLater::new(async { 5 })
169        };
170        use futures_util::FutureExt;
171        assert_eq!(f.now_or_never().expect("future was ready"), 5);
172    }
173
174    #[test]
175    fn only_ready_instantiation() {
176        assert_eq!(
177            NowOrLater::<i32, OnlyReady>::ready(5)
178                .now_or_never()
179                .expect("ready"),
180            5
181        );
182    }
183
184    #[tokio::test]
185    async fn box_dyn_future() {
186        let f = async { 5 };
187        let f = Box::pin(f);
188        let wrapped = NowOrLater::new(f);
189        assert_eq!(wrapped.await, 5);
190    }
191
192    #[tokio::test]
193    async fn async_fn_future() {
194        let wrapped = NowOrLater::new(async { 5 });
195        assert_eq!(wrapped.await, 5);
196    }
197}