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<'a, T, F> NowOrLater<T, F>
129where
130 F: Future<Output = T> + Send + 'a,
131{
132 pub fn map_boxed<U, M>(self, map_fn: M) -> NowOrLater<U, BoxFuture<'a, U>>
145 where
146 M: FnOnce(T) -> U + Send + 'a,
147 {
148 match self.inner {
149 Inner::Now { value } => {
150 let mapped = value.map(map_fn);
151 NowOrLater {
152 inner: Inner::Now { value: mapped },
153 }
154 }
155 Inner::Later { future } => {
156 let fut = async move {
157 let val = future.await;
158 map_fn(val)
159 };
160 NowOrLater {
161 inner: Inner::Later {
162 future: Box::pin(fut),
163 },
164 }
165 }
166 }
167 }
168}
169
170impl<T> NowOrLater<T, OnlyReady> {
171 pub fn map_boxed<U, M>(self, map_fn: M) -> NowOrLater<U, OnlyReady>
173 where
174 M: FnOnce(T) -> U,
175 {
176 match self.inner {
177 Inner::Now { value } => {
178 let mapped = value.map(map_fn);
179 NowOrLater {
180 inner: Inner::Now { value: mapped },
181 }
182 }
183 Inner::Later { .. } => unreachable!(),
184 }
185 }
186}
187
188impl<T, F> Future for NowOrLater<T, F>
189where
190 F: Future<Output = T>,
191{
192 type Output = T;
193
194 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
195 match self.project().inner.project() {
196 NowOrLaterProj::Now { value } => {
197 Poll::Ready(value.take().expect("cannot be called twice"))
198 }
199 NowOrLaterProj::Later { future } => future.poll(cx),
200 }
201 }
202}
203
204impl<T> Future for NowOrLater<T, OnlyReady> {
205 type Output = T;
206
207 fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
208 match self.project().inner.project() {
209 NowOrLaterProj::Now { value } => {
210 Poll::Ready(value.take().expect("cannot be called twice"))
211 }
212 NowOrLaterProj::Later { .. } => unreachable!(),
213 }
214 }
215}
216
217#[cfg(test)]
218mod test {
219 use crate::future::now_or_later::{NowOrLater, OnlyReady};
220 use futures_util::FutureExt;
221
222 #[test]
223 fn ready_future_immediately_returns() {
224 let a = true;
225 let f = if a {
226 NowOrLater::ready(5)
227 } else {
228 NowOrLater::new(async { 5 })
229 };
230 use futures_util::FutureExt;
231 assert_eq!(f.now_or_never().expect("future was ready"), 5);
232 }
233
234 #[test]
235 fn only_ready_instantiation() {
236 assert_eq!(
237 NowOrLater::<i32, OnlyReady>::ready(5)
238 .now_or_never()
239 .expect("ready"),
240 5
241 );
242 }
243
244 #[tokio::test]
245 async fn box_dyn_future() {
246 let f = async { 5 };
247 let f = Box::pin(f);
248 let wrapped = NowOrLater::new(f);
249 assert_eq!(wrapped.await, 5);
250 }
251
252 #[tokio::test]
253 async fn async_fn_future() {
254 let wrapped = NowOrLater::new(async { 5 });
255 assert_eq!(wrapped.await, 5);
256 }
257
258 #[tokio::test]
259 async fn map_boxed_now_variant() {
260 let now: NowOrLater<i32, OnlyReady> = NowOrLater::ready(21);
261 let mapped = now.map_boxed(|x| x * 2);
262 assert_eq!(42, mapped.await);
263 }
264
265 #[tokio::test]
266 async fn map_boxed_later_variant() {
267 let later = NowOrLater::new(async { 10 });
268 let mapped = later.map_boxed(|x| x + 5);
269 assert_eq!(15, mapped.await);
270 }
271}