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::*;