1use core::{
9 fmt::{Debug, Display},
10 future::Future,
11 pin::Pin,
12 task::{Context as TaskContext, Poll},
13};
14
15use crate::{Context, Result, ResultExt};
16
17macro_rules! implement_future_adaptor {
18 ($future:ident, $method:ident, $bound:ident $(+ $bounds:ident)* $(+ $lifetime:lifetime)*, $output:ty) => {
19 #[doc = concat!("Adaptor returned by [`FutureExt::", stringify!( $method ), "`].")]
20 pub struct $future<Fut, T> {
21 future: Fut,
22 inner: Option<T>,
23 }
24
25 impl<Fut, T> Future for $future<Fut, T>
26 where
27 Fut: Future,
28 Fut::Output: ResultExt,
29 T: $bound $(+ $bounds)* $(+ $lifetime)*
30 {
31 type Output = $output;
32
33 #[track_caller]
34 fn poll(self: Pin<&mut Self>, cx: &mut TaskContext) -> Poll<Self::Output> {
35 let (future, inner) = unsafe {
40 let Self { future, inner } = self.get_unchecked_mut();
41 (Pin::new_unchecked(future), inner)
42 };
43
44 match future.poll(cx) {
46 Poll::Ready(value) => {
47 Poll::Ready(value.$method({
48 inner.take().expect("Cannot poll context after it resolves")
49 }))
50 }
51 Poll::Pending => Poll::Pending,
52 }
53 }
54 }
55 };
56}
57
58macro_rules! implement_lazy_future_adaptor {
59 ($future:ident, $method:ident, $bound:ident $(+ $bounds:ident)* $(+ $lifetime:lifetime)*, $output:ty) => {
60 #[doc = concat!("Adaptor returned by [`FutureExt::", stringify!( $method ), "`].")]
61 pub struct $future<Fut, F> {
62 future: Fut,
63 inner: Option<F>,
64 }
65
66 impl<Fut, F, T> Future for $future<Fut, F>
67 where
68 Fut: Future,
69 Fut::Output: ResultExt,
70 F: FnOnce() -> T,
71 T: $bound $(+ $bounds)* $(+ $lifetime)*
72 {
73 type Output = $output;
74
75 #[track_caller]
76 fn poll(self: Pin<&mut Self>, cx: &mut TaskContext) -> Poll<Self::Output> {
77 let (future, inner) = unsafe {
82 let Self { future, inner } = self.get_unchecked_mut();
83 (Pin::new_unchecked(future), inner)
84 };
85
86 match future.poll(cx) {
88 Poll::Ready(value) => {
89 Poll::Ready(value.$method({
90 inner.take().expect("Cannot poll context after it resolves")
91 }))
92 }
93 Poll::Pending => Poll::Pending,
94 }
95 }
96 }
97 };
98}
99
100implement_future_adaptor!(
101 FutureWithAttachment,
102 attach,
103 Send + Sync + 'static,
104 Result<<Fut::Output as ResultExt>::Ok, <Fut::Output as ResultExt>::Context>
105);
106
107implement_lazy_future_adaptor!(
108 FutureWithLazyAttachment,
109 attach_lazy,
110 Send + Sync + 'static,
111 Result<<Fut::Output as ResultExt>::Ok, <Fut::Output as ResultExt>::Context>
112);
113
114implement_future_adaptor!(
115 FutureWithPrintableAttachment,
116 attach_printable,
117 Display + Debug + Send + Sync + 'static,
118 Result<<Fut::Output as ResultExt>::Ok, <Fut::Output as ResultExt>::Context>
119);
120
121implement_lazy_future_adaptor!(
122 FutureWithLazyPrintableAttachment,
123 attach_printable_lazy,
124 Display + Debug + Send + Sync + 'static,
125 Result<<Fut::Output as ResultExt>::Ok, <Fut::Output as ResultExt>::Context>
126);
127
128implement_future_adaptor!(
129 FutureWithContext,
130 change_context,
131 Context,
132 Result<<Fut::Output as ResultExt>::Ok, T>
133);
134
135implement_lazy_future_adaptor!(
136 FutureWithLazyContext,
137 change_context_lazy,
138 Context,
139 Result<<Fut::Output as ResultExt>::Ok, T>
140);
141
142pub trait FutureExt: Future + Sized {
146 #[track_caller]
155 fn attach<A>(self, attachment: A) -> FutureWithAttachment<Self, A>
156 where
157 A: Send + Sync + 'static;
158
159 #[track_caller]
168 fn attach_lazy<A, F>(self, attachment: F) -> FutureWithLazyAttachment<Self, F>
169 where
170 A: Send + Sync + 'static,
171 F: FnOnce() -> A;
172
173 #[track_caller]
183 fn attach_printable<A>(self, attachment: A) -> FutureWithPrintableAttachment<Self, A>
184 where
185 A: Display + Debug + Send + Sync + 'static;
186
187 #[track_caller]
197 fn attach_printable_lazy<A, F>(
198 self,
199 attachment: F,
200 ) -> FutureWithLazyPrintableAttachment<Self, F>
201 where
202 A: Display + Debug + Send + Sync + 'static,
203 F: FnOnce() -> A;
204
205 #[track_caller]
214 fn change_context<C>(self, context: C) -> FutureWithContext<Self, C>
215 where
216 C: Context;
217
218 #[track_caller]
227 fn change_context_lazy<C, F>(self, context: F) -> FutureWithLazyContext<Self, F>
228 where
229 C: Context,
230 F: FnOnce() -> C;
231}
232
233impl<Fut: Future> FutureExt for Fut
234where
235 Fut::Output: ResultExt,
236{
237 fn attach<A>(self, attachment: A) -> FutureWithAttachment<Self, A>
238 where
239 A: Send + Sync + 'static,
240 {
241 FutureWithAttachment {
242 future: self,
243 inner: Some(attachment),
244 }
245 }
246
247 #[track_caller]
248 fn attach_lazy<A, F>(self, attachment: F) -> FutureWithLazyAttachment<Self, F>
249 where
250 A: Send + Sync + 'static,
251 F: FnOnce() -> A,
252 {
253 FutureWithLazyAttachment {
254 future: self,
255 inner: Some(attachment),
256 }
257 }
258
259 #[track_caller]
260 fn attach_printable<A>(self, attachment: A) -> FutureWithPrintableAttachment<Self, A>
261 where
262 A: Display + Debug + Send + Sync + 'static,
263 {
264 FutureWithPrintableAttachment {
265 future: self,
266 inner: Some(attachment),
267 }
268 }
269
270 #[track_caller]
271 fn attach_printable_lazy<A, F>(
272 self,
273 attachment: F,
274 ) -> FutureWithLazyPrintableAttachment<Self, F>
275 where
276 A: Display + Debug + Send + Sync + 'static,
277 F: FnOnce() -> A,
278 {
279 FutureWithLazyPrintableAttachment {
280 future: self,
281 inner: Some(attachment),
282 }
283 }
284
285 #[track_caller]
286 fn change_context<C>(self, context: C) -> FutureWithContext<Self, C>
287 where
288 C: Context,
289 {
290 FutureWithContext {
291 future: self,
292 inner: Some(context),
293 }
294 }
295
296 #[track_caller]
297 fn change_context_lazy<C, F>(self, context: F) -> FutureWithLazyContext<Self, F>
298 where
299 C: Context,
300 F: FnOnce() -> C,
301 {
302 FutureWithLazyContext {
303 future: self,
304 inner: Some(context),
305 }
306 }
307}