Check if a future is ready without consuming it

Is there a way to check if a future is ready without consuming it ?

Current code:

pub async fn {
  ...
  x.await();
}

Right now, the x.await() blocks the task until x is ready.

Is there some way to get a bool informing us whether x is ready ?

Poll it?

You can use now_or_never from the futures crate to poll it once, which doesn't consume it if called on a mutable reference. However, this will still poll it once, and you can't "put back" the return value if it completes - polling it again after completion will panic.

3 Likes

There's std::future::Future::poll, but then you have to handle the case when the future is actually Ready and do something with the produced value.

This can lose the value if the future expects to be woken.

No, situations in which one uses now_or_never, the future generally can't tell the difference between using a dummy waker or using the task's actual waker.

Regarding all the suggestions of 'poll it'.

  1. I understand this definition:
pub enum Poll<T> {
    Ready(T),
    Pending,
}
  1. I also understand we have this definition:
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>

However, I see the following problems.

  1. To the best of my knowledge, except for fused futures, we are NOT allowed to poll it again after it returns Ready. I.e. the Future is within it's right to panic or cause UB if we do so.

  2. The above 'poll' ends up "consuming the output" -- if we get a Ready, we are not supposed to poll it again.

Other random thought

If we take a step back, is the right solution to use select + fused futures, with a default branch ?

I suppose one option is to use this utility:

It's not exposed publicly, though.

The poll method is not unsafe, so it may not cause UB. It may cause any other types of havoc though.

2 Likes

futures has a public MaybeDone, so you don't need to copy tokio internals.

If you don't need MaybeDone's feature of storing the output, but can deal with immediately using it and not polling again, then futures::poll! suffices — it solves the problem of passing on the Context from the current function, and nothing else.

A macro which returns the result of polling a future once within the current async context.