How to call async fn() in Future::poll()?

I'm calling an async fn() in Future::poll() but the .await statement and the code behind it is not executed at the time of execution.

/*

Cargo.toml:


[package]
name = "test-poll"
version = "0.1.0"
authors = ["xx <xx@xx.com>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
async-std="1.8.0"
pin-project="0.4.6"
futures=""

*/

use std::future::Future;
use std::task::{Context, Poll};
use std::pin::Pin;
use std::sync::{Arc,Mutex};
use futures::FutureExt;

#[pin_project::pin_project]
struct Person<'a> {
    name: &'a str,
    age: i32,
}

impl<'a> Future for Person<'a> {
    type Output = i32;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        let mut this = self.project();
        *this.age += 10;

        let mut fut1 = fn1();
        let pinfut1 =  Pin::new(&mut fut1);
        //let pinfut1 = unsafe { Pin::new_unchecked(&mut fut1) };
        pinfut1.poll(cx)
    }
}

fn fn1() -> impl Future<Output=i32> + Unpin {
    async {
        dbg!("sleep start!"); // execute here!
        async_std::task::sleep(std::time::Duration::from_secs(5)).await; //  <--- blocked here ?
        dbg!("sleep done!"); // Never execute here!
        123
    }.boxed()
}

fn main() {
    let p1 = Person {name: "jack", age: Default::default()};
    async_std::task::block_on(async {
        let a = p1.await;
        dbg!(a); // Never execute here!
    });
    std::thread::park();
}

(Playground)

You need to store the future in your struct such that you can repeatedly call poll on the same future object across several calls to Person::poll.

Or you can replace the manual impl Future with a method to the Person<'a> like async fn do_something(self) {...} and fn1().await in it.

2 Likes

can you give the code ?

use std::pin::Pin;
use std::task::{Context, Poll};
use std::future::Future;
use futures::future::BoxFuture;

#[pin_project::pin_project]
struct Person<'a> {
    name: &'a str,
    age: i32,
    #[pin]
    future: Option<BoxFuture<'static, i32>>,
}

impl<'a> Future for Person<'a> {
    type Output = i32;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        let mut this = self.project();
        *this.age += 10;

        if this.future.is_none() {
            *this.future = Some(Box::pin(fn1()));
        }

        this.future
            .as_pin_mut()
            .unwrap()
            .poll(cx)
    }
}

async fn fn1() -> i32 {
    ...
}
1 Like