1#![expect(deprecated, reason = "We use `Context` to maintain compatibility")]
2use core::{
10 future::Future,
11 pin::Pin,
12 task::{Context as TaskContext, Poll},
13};
14
15use crate::{Attachment, Context, OpaqueAttachment, Report, 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 Attachment,
104 Result<<Fut::Output as ResultExt>::Ok, Report<<Fut::Output as ResultExt>::Context>>
105);
106
107implement_lazy_future_adaptor!(
108 FutureWithLazyAttachment,
109 attach_with,
110 Attachment,
111 Result<<Fut::Output as ResultExt>::Ok, Report<<Fut::Output as ResultExt>::Context>>
112);
113
114implement_future_adaptor!(
115 FutureWithOpaqueAttachment,
116 attach_opaque,
117 OpaqueAttachment,
118 Result<<Fut::Output as ResultExt>::Ok, Report<<Fut::Output as ResultExt>::Context>>
119);
120
121implement_lazy_future_adaptor!(
122 FutureWithLazyOpaqueAttachment,
123 attach_opaque_with,
124 OpaqueAttachment,
125 Result<<Fut::Output as ResultExt>::Ok, Report<<Fut::Output as ResultExt>::Context>>
126);
127
128implement_future_adaptor!(
129 FutureWithContext,
130 change_context,
131 Context,
132 Result<<Fut::Output as ResultExt>::Ok, Report<T>>
133);
134
135implement_lazy_future_adaptor!(
136 FutureWithLazyContext,
137 change_context_lazy,
138 Context,
139 Result<<Fut::Output as ResultExt>::Ok, Report<T>>
140);
141
142pub trait FutureExt: Future + Sized {
146 #[track_caller]
156 fn attach<A>(self, attachment: A) -> FutureWithAttachment<Self, A>
157 where
158 A: Attachment;
159
160 #[track_caller]
170 fn attach_with<A, F>(self, attachment: F) -> FutureWithLazyAttachment<Self, F>
171 where
172 A: Attachment,
173 F: FnOnce() -> A;
174
175 #[deprecated(
176 note = "Use `attach_opaque_with` instead. `attach_lazy` was renamed to \
177 `attach_opaque_with` and `attach_printable_lazy` was renamed to `attach_with`",
178 since = "0.6.0"
179 )]
180 #[track_caller]
181 fn attach_lazy<A, F>(self, attachment: F) -> FutureWithLazyOpaqueAttachment<Self, F>
182 where
183 A: OpaqueAttachment,
184 F: FnOnce() -> A;
185
186 #[track_caller]
195 fn attach_opaque<A>(self, attachment: A) -> FutureWithOpaqueAttachment<Self, A>
196 where
197 A: OpaqueAttachment;
198
199 #[track_caller]
208 fn attach_opaque_with<A, F>(self, attachment: F) -> FutureWithLazyOpaqueAttachment<Self, F>
209 where
210 A: OpaqueAttachment,
211 F: FnOnce() -> A;
212
213 #[track_caller]
214 #[deprecated(
215 note = "Use `attach` instead. `attach` was renamed to `attach_opaque` and \
216 `attach_printable` was renamed to `attach`",
217 since = "0.6.0"
218 )]
219 #[inline]
220 fn attach_printable<A>(self, attachment: A) -> FutureWithAttachment<Self, A>
221 where
222 A: Attachment,
223 {
224 self.attach(attachment)
225 }
226
227 #[track_caller]
228 #[deprecated(
229 note = "Use `attach_with` instead. `attach_lazy` was renamed to `attach_opaque_with` and \
230 `attach_printable_lazy` was renamed to `attach_with`",
231 since = "0.6.0"
232 )]
233 #[inline]
234 fn attach_printable_lazy<A, F>(self, attachment: F) -> FutureWithLazyAttachment<Self, F>
235 where
236 A: Attachment,
237 F: FnOnce() -> A,
238 {
239 self.attach_with(attachment)
240 }
241
242 #[track_caller]
251 fn change_context<C>(self, context: C) -> FutureWithContext<Self, C>
252 where
253 C: Context;
254
255 #[track_caller]
264 fn change_context_lazy<C, F>(self, context: F) -> FutureWithLazyContext<Self, F>
265 where
266 C: Context,
267 F: FnOnce() -> C;
268}
269
270impl<Fut: Future> FutureExt for Fut
271where
272 Fut::Output: ResultExt,
273{
274 #[track_caller]
275 fn attach<A>(self, attachment: A) -> FutureWithAttachment<Self, A>
276 where
277 A: Attachment,
278 {
279 FutureWithAttachment {
280 future: self,
281 inner: Some(attachment),
282 }
283 }
284
285 #[track_caller]
286 fn attach_with<A, F>(self, attachment: F) -> FutureWithLazyAttachment<Self, F>
287 where
288 A: Attachment,
289 F: FnOnce() -> A,
290 {
291 FutureWithLazyAttachment {
292 future: self,
293 inner: Some(attachment),
294 }
295 }
296
297 #[track_caller]
298 fn attach_lazy<A, F>(self, attachment: F) -> FutureWithLazyOpaqueAttachment<Self, F>
299 where
300 A: OpaqueAttachment,
301 F: FnOnce() -> A,
302 {
303 FutureWithLazyOpaqueAttachment {
304 future: self,
305 inner: Some(attachment),
306 }
307 }
308
309 fn attach_opaque<A>(self, attachment: A) -> FutureWithOpaqueAttachment<Self, A>
310 where
311 A: OpaqueAttachment,
312 {
313 FutureWithOpaqueAttachment {
314 future: self,
315 inner: Some(attachment),
316 }
317 }
318
319 #[track_caller]
320 fn attach_opaque_with<A, F>(self, attachment: F) -> FutureWithLazyOpaqueAttachment<Self, F>
321 where
322 A: OpaqueAttachment,
323 F: FnOnce() -> A,
324 {
325 FutureWithLazyOpaqueAttachment {
326 future: self,
327 inner: Some(attachment),
328 }
329 }
330
331 #[track_caller]
332 fn change_context<C>(self, context: C) -> FutureWithContext<Self, C>
333 where
334 C: Context,
335 {
336 FutureWithContext {
337 future: self,
338 inner: Some(context),
339 }
340 }
341
342 #[track_caller]
343 fn change_context_lazy<C, F>(self, context: F) -> FutureWithLazyContext<Self, F>
344 where
345 C: Context,
346 F: FnOnce() -> C,
347 {
348 FutureWithLazyContext {
349 future: self,
350 inner: Some(context),
351 }
352 }
353}