Something like this should work (I did some light testing):
use std::pin::Pin;
use std::task::{Poll, LocalWaker};
use futures_util::future::FutureExt;
pub struct Force<A> {
future: Option<Pin<Box<A>>>,
}
impl<A> Force<A> {
#[inline]
pub fn new(future: A) -> Self {
Self {
future: Some(Box::pin(future)),
}
}
}
impl<A> Unpin for Force<A> {}
impl<A> Future for Force<A> where A: Future {
type Output = Deferred<A>;
fn poll(mut self: Pin<&mut Self>, lw: &LocalWaker) -> Poll<Self::Output> {
let mut future = self.future.take().unwrap();
match future.poll_unpin(lw) {
Poll::Ready(value) => Poll::Ready(Deferred {
state: DeferredState::Ready(Some(value)),
}),
Poll::Pending => Poll::Ready(Deferred {
state: DeferredState::Pending(future),
}),
}
}
}
enum DeferredState<A> where A: Future {
Ready(Option<A::Output>),
Pending(Pin<Box<A>>),
}
pub struct Deferred<A> where A: Future {
state: DeferredState<A>,
}
impl<A> Unpin for Deferred<A> where A: Future {}
impl<A> Future for Deferred<A> where A: Future {
type Output = A::Output;
fn poll(mut self: Pin<&mut Self>, lw: &LocalWaker) -> Poll<Self::Output> {
match &mut self.state {
DeferredState::Ready(value) => Poll::Ready(value.take().unwrap()),
DeferredState::Pending(future) => future.poll_unpin(lw),
}
}
}
You use it like this:
async fn foo() {
let x = await!(Force::new(bar()));
...
let y = await!(x);
}
Basically, Force::new
returns a Future
which immediately polls bar()
, and then you can later retrieve the value by awaiting on x
.
This does have some overhead (a Box
heap allocation), but perhaps that can be fixed with some trickery.
I’m not actually sure how to express this with implicit await
. Maybe something like this?
async fn foo() {
let x = async { Force::new(bar()) };
...
let y = await!(x);
}
I haven’t looked too deeply at the various implicit async proposals, so I’m not sure how they handle deferred Futures.
I know they usually use async { ... }
to do the actual deferral, but then how do they await the deferred Future?