How to check if a future is immediately ready?

How to poll a future once and check if it isn't ready before awaiting it?
I know there is once_or_never but that unfortunately consumes the future and if it wasn't ready, then the result is lost.

Something like:

let fut = call_some_async_fn();
if !fut.is_ready() {   // poll the future once
   println!("will have to wait...");
}
fut.await

You can use now_or_never without consuming it like this:

let fut = call_some_async_fn();
tokio::pin!(fut);
if let Some(output) = fut.as_mut().now_or_never() {
    println!("got output {:?}", output);
} else {
    fut.await;
}

The way this works is that tokio::pin! creates a new fut variable of type Pin<&mut FutType>, and Pin provides an .as_mut() method that returns a sub-reference that you can consume without consuming the original Pin.

For futures that don't need to be pinned (these are pretty rare - mostly they come from StreamExt), you can also just use a mutable reference like this: (&mut fut).now_or_never()

Warning: This doesn't consume the future even if it returns Some. Awaiting or otherwise polling it again after completion will lead to a panic.

2 Likes

I ended up with a much more complex solution trying to get a std::task::Context to be able to invoke std::future::Future::poll somehow. Meanwhile @alice posted a much better solution, but here's my (non-idiomatic) result anyway:

use std::future::Future;
use std::marker::Unpin;
use std::pin::Pin;
use std::task::{Context, Poll};

pub struct PolledFuture<T>(Option<T>);

impl<T> PolledFuture<T> {
    pub fn new(future: T) -> Self {
        Self(Some(future))
    }
}

impl<T, O> Future for PolledFuture<T>
where
    T: Future<Output = O> + Unpin,
{
    type Output = Result<O, Self>;
    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<O, Self>> {
        let mut inner = self.0.take().unwrap();
        let poll = Pin::new(&mut inner).poll(cx);
        Poll::Ready(
            match poll {
                Poll::Ready(x) => Ok(x),
                Poll::Pending => Err(PolledFuture(Some(inner))),
            }
        )
    }
}

#[tokio::main]
async fn main() {
    let f = tokio::time::sleep(std::time::Duration::from_millis(100));
    let polled_f = PolledFuture::new(Box::pin(f));
    let polled_f = match polled_f.await {
        Ok(()) => {
            println!("Completed already.");
            return;
        }
        Err(fut) => {
            println!("Not completed yet.");
            fut
        }
    };
    std::thread::sleep(std::time::Duration::from_millis(200));
    let polled_f = match polled_f.await {
        Ok(()) => {
            println!("Completed finally.");
            return;
        }
        Err(fut) => {
            println!("Still not completed.");
            fut
        }
    };
    drop(polled_f);
}

(Playground)

Output:

Not completed yet.
Completed finally.

In that code, I didn't know about std::pin::Pin::as_mut yet. Hency my clumsy approach of returning a new future as a Result::Err for the case where the inner future didn't resolve.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.