aws_smithy_async/future/
now_or_later.rs
1use 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}