owned_future/
funcs.rs

1use core::{
2    future::pending,
3    mem::MaybeUninit,
4    pin::Pin,
5    sync::atomic::AtomicPtr,
6    task::{Context, Poll, Waker},
7};
8
9use alloc::boxed::Box;
10
11use crate::{GetFut, TryGetFut};
12
13struct PollOnce {
14    completed: bool,
15}
16
17impl Future for PollOnce {
18    type Output = ();
19    fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
20        if !self.completed {
21            self.completed = true;
22            Poll::Pending
23        } else {
24            Poll::Ready(())
25        }
26    }
27}
28
29/// Encapsulate a borrowed-future along with it's owner.
30///
31/// This function takes the owner by value and a functor-like [`GetFut`], which when invoked will
32/// return a borrowed-future.'
33///
34/// The future returned by this function takes ownership of the owner, and will `.await` the
35/// borrowed-future when polled.
36///
37/// Callers may wish to use [`crate::get`] to quickly construct this functor for cases which don't
38/// require capturing, but any type which implements `GetFut` will work.
39#[deny(unsafe_code)]
40pub fn make<G>(val: G::Input, getter: G) -> Pin<Box<impl Future<Output = G::Output>>>
41where
42    G: GetFut,
43{
44    let mut future = Box::pin(async move {
45        let mut val = val;
46        let future = getter.get_fut(&mut val);
47        PollOnce { completed: false }.await;
48        future.await
49    });
50
51    let _poll = Future::poll(future.as_mut(), &mut Context::from_waker(Waker::noop()));
52    debug_assert!(matches!(_poll, Poll::Pending));
53
54    future
55}
56
57/// Try to encapsulate a borrowed-future along with it's owner.
58///
59/// This function takes the owner by value and a functor-like [`TryGetFut`], which when invoked will
60/// return a borrowed-future.
61///
62/// In the case that functor returns an error, this function will return that error along with the
63/// owner. When the functor return a borrowed-future, this function returns a future which has taken
64/// ownership of the owner, and will `.await` the borrowed-future when polled. Auxiliary data
65/// returned by the functor is also returned in this case.
66///
67/// Callers may wish to use [`crate::try_get`] to quickly construct this functor for cases which
68/// don't require capturing, but any type which implements `TryGetFut` will work.
69pub fn try_make<G>(
70    val: G::Input,
71    getter: G,
72) -> Result<(Pin<Box<impl Future<Output = G::Output>>>, G::Aux), (G::Input, G::Error)>
73where
74    G: TryGetFut,
75{
76    let mut result = MaybeUninit::<Result<G::Aux, (G::Input, G::Error)>>::uninit();
77    let result_ptr = AtomicPtr::new(result.as_mut_ptr());
78    let mut future = Box::pin(async move {
79        let mut val = val;
80        let result_ptr = result_ptr.into_inner();
81
82        let err = 'err: {
83            match getter.try_get_fut(&mut val) {
84                Ok((future, aux)) => {
85                    // SAFETY: this is safe to do because `result_ptr` lives in the stack frame
86                    // above us and we write to it exactly once prior to the first poll
87                    unsafe {
88                        result_ptr.write(Ok(aux));
89                    }
90
91                    // return `Pending` and pass control back
92                    PollOnce { completed: false }.await;
93
94                    return future.await;
95                }
96                Err(err) => break 'err err,
97            }
98        };
99
100        // SAFETY: this is safe to do because `result_ptr` lives in the stack frame above us and we
101        // write to it exactly once prior to the first poll
102        unsafe {
103            result_ptr.write(Err((val, err)));
104        }
105
106        // return `Pending` and pass control back
107        pending::<()>().await;
108
109        // The future should be forgotten and this should never be called
110        unreachable!();
111    });
112
113    let _poll = Future::poll(future.as_mut(), &mut Context::from_waker(Waker::noop()));
114    debug_assert!(matches!(_poll, Poll::Pending));
115
116    // SAFETY: this is safe to do because `result` is always written exactly once and always before
117    // the first poll
118    let result = unsafe { result.assume_init() };
119
120    result.map(|aux| (future, aux))
121}
122
123#[cfg(feature = "async")]
124mod async_feature {
125    use core::{
126        future::pending,
127        mem,
128        pin::Pin,
129        sync::atomic::AtomicPtr,
130        task::{Context, Poll},
131    };
132
133    use alloc::boxed::Box;
134    use pin_project_lite::pin_project;
135
136    use crate::{AsyncSendTryGetFut, AsyncTryGetFut, funcs::PollOnce};
137
138    enum AsyncTryMakeFuture<'a, G: AsyncTryGetFut<'a>> {
139        Input(G::Input, G),
140        Future(Pin<Box<dyn 'a + Future<Output = G::Output>>>),
141        Done,
142    }
143
144    pin_project! {
145        /// Try to encapsulate an `async`-constructed borrowed-future along with it's owner.
146        ///
147        /// This struct only works with `!Send` futures. If you're working with `Send`-futures,
148        /// try using [`AsyncSendTry`].
149        ///
150        /// This struct can be constructed by passing to [`Self::new`] the owner by value and a
151        /// functor-like [`AsyncTryGetFut`], which when invoked will return a borrowed-future.'
152        ///
153        /// In contrast to the method helpers in this crate, this structure is a future which must
154        /// be polled in order to acquire the owned-future. Polling this future will first poll the
155        /// functor until it results in either an error, in which case this future will yield that
156        /// same error along with the owner, or a borrowed-future, in which ase this future will
157        /// yield a future which has taken ownership of the owner, and will `.await` the borrowed
158        /// future when polled. Auxiliary data returned by the functor is also yielded in this case.
159        ///
160        /// Callers may wish to use [`crate::async_try_get`] to quickly construct the functor for
161        /// cases which don't require capturing, but any type which implements `AsyncTryGetFut` will
162        /// work.
163        pub struct AsyncTry<'a, G: AsyncTryGetFut<'a>> {
164            result: Option<Result<G::Aux, (G::Input, G::Error)>>,
165            future: AsyncTryMakeFuture<'a, G>
166        }
167    }
168
169    impl<'a, G: AsyncTryGetFut<'a>> AsyncTry<'a, G> {
170        /// Construct the `AsyncTry` from an owner and a borrowed-future functor
171        pub fn new(val: G::Input, getter: G) -> Self {
172            Self {
173                result: None,
174                future: AsyncTryMakeFuture::Input(val, getter),
175            }
176        }
177    }
178
179    /// An alias for the output type of [`AsyncTry`]
180    ///
181    /// This will stop being `Box<dyn _>` once either `type_alias_impl_trait` or
182    /// `impl_trait_in_assoc_type` stabilize
183    pub type AsyncTryOutput<'a, G> = Result<
184        (
185            Pin<Box<dyn 'a + Future<Output = <G as AsyncTryGetFut<'a>>::Output>>>,
186            <G as AsyncTryGetFut<'a>>::Aux,
187        ),
188        (
189            <G as AsyncTryGetFut<'a>>::Input,
190            <G as AsyncTryGetFut<'a>>::Error,
191        ),
192    >;
193
194    impl<'a, G: AsyncTryGetFut<'a>> Future for AsyncTry<'a, G> {
195        type Output = AsyncTryOutput<'a, G>;
196
197        fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
198            let future = match mem::replace(&mut self.future, AsyncTryMakeFuture::Done) {
199                AsyncTryMakeFuture::Done => unreachable!(),
200                AsyncTryMakeFuture::Input(val, getter) => {
201                    let result_ptr = AtomicPtr::new(&mut self.result);
202
203                    let mut future = Box::pin(async move {
204                        let mut val = val;
205                        let result_ptr = result_ptr.into_inner();
206                        let err = 'err: {
207                            match getter.async_try_get_fut(&mut val).await {
208                                Ok((future, aux)) => {
209                                    // SAFETY: this is safe to do because `result_ptr` is pinned by our
210                                    // poller and we write to it exactly once
211                                    unsafe {
212                                        debug_assert!((*result_ptr).is_none());
213                                        *result_ptr = Some(Ok(aux));
214                                    }
215
216                                    // return `Pending` and pass control back
217                                    PollOnce { completed: false }.await;
218
219                                    return future.await;
220                                }
221                                Err(err) => break 'err err,
222                            }
223                        };
224                        // SAFETY: this is safe to do because `result_ptr` is pinned by our poller and
225                        // we write to it exactly once
226                        unsafe {
227                            debug_assert!((*result_ptr).is_none());
228                            *result_ptr = Some(Err((val, err)));
229                        }
230
231                        // return `Pending` and pass control back
232                        pending::<()>().await;
233
234                        // The future should be forgotten and this should never be called
235                        unreachable!();
236                    });
237                    let _result = future.as_mut().poll(cx);
238                    debug_assert!(matches!(_result, Poll::Pending));
239                    future
240                }
241                AsyncTryMakeFuture::Future(mut future) => {
242                    let _result = future.as_mut().poll(cx);
243                    debug_assert!(matches!(_result, Poll::Pending));
244                    future
245                }
246            };
247
248            if let Some(result) = self.result.take() {
249                return Poll::Ready(result.map(|aux| (future, aux)));
250            }
251            self.future = AsyncTryMakeFuture::Future(future);
252
253            Poll::Pending
254        }
255    }
256
257    enum AsyncSendTryMakeFuture<'a, G: AsyncSendTryGetFut<'a>> {
258        Input(G::Input, G),
259        Future(Pin<Box<dyn 'a + Send + Future<Output = G::Output>>>),
260        Done,
261    }
262
263    pin_project! {
264        /// Try to encapsulate an `async`-constructed borrowed-future along with it's owner.
265        ///
266        /// This struct only works with `Send` futures. If you're working with `!Send`-futures,
267        /// try using [`AsyncTry`].
268        ///
269        /// This struct can be constructed by passing to [`Self::new`] the owner by value and a
270        /// functor-like [`AsyncSendTryGetFut`], which when invoked will return a borrowed-future.'
271        ///
272        /// In contrast to the method helpers in this crate, this structure is a future which must
273        /// be polled in order to acquire the owned-future. Polling this future will first poll the
274        /// functor until it results in either an error, in which case this future will yield that
275        /// same error along with the owner, or a borrowed-future, in which ase this future will
276        /// yield a future which has taken ownership of the owner, and will `.await` the borrowed
277        /// future when polled. Auxiliary data returned by the functor is also yielded in this case.
278        ///
279        /// Callers may wish to use [`crate::async_send_try_get`] to quickly construct the functor
280        /// for cases which don't require capturing, but any type which implements `AsyncTryGetFut`
281        /// will work.
282        pub struct AsyncSendTry<'a, G: AsyncSendTryGetFut<'a>> {
283            result: Option<Result<G::Aux, (G::Input, G::Error)>>,
284            future: AsyncSendTryMakeFuture<'a, G>
285        }
286    }
287
288    impl<'a, G: AsyncSendTryGetFut<'a>> AsyncSendTry<'a, G> {
289        pub fn new(val: G::Input, getter: G) -> Self {
290            Self {
291                result: None,
292                future: AsyncSendTryMakeFuture::Input(val, getter),
293            }
294        }
295    }
296
297    /// An alias for the output type of [`AsyncSendTry`]
298    ///
299    /// This will stop being `Box<dyn _>` once either `type_alias_impl_trait` or
300    /// `impl_trait_in_assoc_type` stabilize
301    pub type AsyncSendTryOutput<'a, G> = Result<
302        (
303            Pin<Box<dyn 'a + Send + Future<Output = <G as AsyncSendTryGetFut<'a>>::Output>>>,
304            <G as AsyncSendTryGetFut<'a>>::Aux,
305        ),
306        (
307            <G as AsyncSendTryGetFut<'a>>::Input,
308            <G as AsyncSendTryGetFut<'a>>::Error,
309        ),
310    >;
311
312    impl<'a, G: AsyncSendTryGetFut<'a>> Future for AsyncSendTry<'a, G> {
313        type Output = AsyncSendTryOutput<'a, G>;
314
315        fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
316            let future = match mem::replace(&mut self.future, AsyncSendTryMakeFuture::Done) {
317                AsyncSendTryMakeFuture::Done => unreachable!(),
318                AsyncSendTryMakeFuture::Input(val, getter) => {
319                    let result_ptr = AtomicPtr::new(&mut self.result);
320
321                    let mut future = Box::pin(async move {
322                        let mut val = val;
323                        let err = 'err: {
324                            match getter.async_send_try_get_fut(&mut val).await {
325                                Ok((future, aux)) => {
326                                    let result_ptr = result_ptr.into_inner();
327                                    // SAFETY: this is safe to do because `result_ptr` is pinned by our
328                                    // poller and we write to it exactly once
329                                    unsafe {
330                                        debug_assert!((*result_ptr).is_none());
331                                        *result_ptr = Some(Ok(aux));
332                                    }
333
334                                    // return `Pending` and pass control back
335                                    PollOnce { completed: false }.await;
336
337                                    return future.await;
338                                }
339                                Err(err) => break 'err err,
340                            }
341                        };
342                        let result_ptr = result_ptr.into_inner();
343                        // SAFETY: this is safe to do because `result_ptr` is pinned by our poller and
344                        // we write to it exactly once
345                        unsafe {
346                            debug_assert!((*result_ptr).is_none());
347                            *result_ptr = Some(Err((val, err)));
348                        }
349
350                        // return `Pending` and pass control back
351                        pending::<()>().await;
352
353                        // The future should be forgotten and this should never be called
354                        unreachable!();
355                    });
356                    let _result = future.as_mut().poll(cx);
357                    debug_assert!(matches!(_result, Poll::Pending));
358                    // todo!("blocked on rust-lang/rust#100013")
359                    future
360                }
361                AsyncSendTryMakeFuture::Future(mut future) => {
362                    let _result = future.as_mut().poll(cx);
363                    debug_assert!(matches!(_result, Poll::Pending));
364                    future
365                }
366            };
367
368            if let Some(result) = self.result.take() {
369                return Poll::Ready(result.map(|aux| (future, aux)));
370            }
371            self.future = AsyncSendTryMakeFuture::Future(future);
372
373            Poll::Pending
374        }
375    }
376}
377
378#[cfg(feature = "async")]
379pub use async_feature::*;