LunarEclipse
LunarEclipse

Reputation: 1011

How does Rust implement await keyword?

As far as I know, Rust's await called on a future seems to call the poll method of the future. However, the poll method needs a context parameter, if I manually call the poll method on a future, I need an executor to produce a context so a waker can be produced to call wake() on. But how the compiler knows how to get a context?

Upvotes: 4

Views: 861

Answers (1)

Chayim Friedman
Chayim Friedman

Reputation: 71300

Since await is only allowed inside async functions (or blocks), you already have a context. It is hidden from you, but the compiler can access it.

If you're interested in the exact way this works, you can inspect the HIR. A function like that:

async fn bar() {
    foo().await;
}

Generates something like the following (you can choose "Show HIR" in the playground):

fn bar() -> impl Future {
    std::future::from_generator(move |mut _task_context| {
        let _t = {
            match std::future::IntoFuture::into_future(foo()) {
                mut __awaitee => loop {
                    match unsafe {
                        std::future::Future::poll(
                            std::pin::Pin::new_unchecked(&mut __awaitee),
                            std::future::get_context(_task_context),
                        )
                    } {
                        std::task::Poll::Ready { 0: result } => break result,
                        std::task::Poll::Pending {} => {}
                    }
                    _task_context = (yield ());
                },
            };
        };
        _t
    })
}

You can see the compiler uses the hidden _task_context parameter.

The code in the compiler that is responsible for await lowering can be found here.

Upvotes: 7

Related Questions