Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can one await a result of a boxed future?

use futures::{future, Future};

fn test() -> Box<dyn Future<Output = bool>> {
    Box::new(future::ok::<bool>(true))
}

async fn async_fn() -> bool {
    let result: bool = test().await;
    return result;
}

fn main(){
    async_fn();
    println!("Hello!");
}

Playground

Error:

error[E0277]: the trait bound `dyn core::future::future::Future<Output = bool>: std::marker::Unpin` is not satisfied
  --> src/main.rs:8:24
   |
8  |     let result: bool = test().await;
   |                        ^^^^^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `dyn core::future::future::Future<Output = bool>`
   |
   = note: required because of the requirements on the impl of `core::future::future::Future` for `std::boxed::Box<dyn core::future::future::Future<Output = bool>>`
like image 359
Techradar Avatar asked Mar 06 '20 09:03

Techradar


People also ask

What are the method of telling Tokio about future?

The poll method The core method of future, poll , is used to attempt to generate the value of a Future . This method does not block but is allowed to inform the caller that the value is not ready yet.

What is a future in Rust?

A future represents an asynchronous computation obtained by use of async . A future is a value that might not have finished computing yet. This kind of “asynchronous value” makes it possible for a thread to continue doing useful work while it waits for the value to become available.


2 Answers

When it comes to Box and future, it almost always make sense to use Box::pin instead of Box::new:

use std::pin::Pin;
use futures::{future, Future};

fn test() -> Pin<Box<dyn Future<Output = Result<bool, ()>>>> {
    Box::pin(future::ok(true))
}

async fn async_fn() -> bool {
    test().await.unwrap()
}

The reason is quite interesting. Pin has a blanket implementation for Unpin:

impl<P> Unpin for Pin<P> where
    P: Unpin,

And the Box<T> inside it is unconditionally Unpin:

impl<T> Unpin for Box<T> where
    T: ?Sized,

So a Pin<Box<dyn Future>> is a unpinned Future. Everything works out, but why Box itself doesn't? This is one place where Deref gets in the way:

impl<T: ?Sized> Deref for Box<T> {
    type Target = T;
}

await expects an unpinned Future, and the Box<dyn Future> you created with Box::new does contain a Future. So it is auto-dereferenced and the Unpin is lost unless you explicitly state it that way with Box<dyn Future + Unpin>.


Edit: @ÖmerErden is right about why Box<dyn Future> wouldn't work.

like image 183
edwardw Avatar answered Oct 06 '22 03:10

edwardw


According to the implementation:

impl<F> Future for Box<F>
where
    F: Unpin + Future + ?Sized, 

Boxed futures only implement the Future trait when the future inside the Box implements Unpin.

Since your function doesn't guarantee that the returned future implements Unpin, your return value will be considered to not implement Future. You'll not able to await it because your type is basically not a Future.

The solution from @Stargateur, adding an explicit type boundary to the signature, works (Playground):

fn test() -> Box<dyn Future<Output = Result<bool, ()>> + Unpin> 

If you are using futures-rs, there is a helper type BoxFuture. You can use BoxedFuture without explicitly stating Unpin:

use futures::future::BoxFuture;

fn test() -> BoxFuture<'static, Result<bool, ()>> {
    Box::pin(async { Ok(true) })
}

Playground

like image 41
Ömer Erden Avatar answered Oct 06 '22 03:10

Ömer Erden