blob: 79e7c400da8947750800cd2d24532939f5357c62 [file] [log] [blame] [view]
r[expr.await]
# Await expressions
r[expr.await.syntax]
```grammar,expressions
AwaitExpression -> Expression `.` `await`
```
r[expr.await.intro]
An `await` expression is a syntactic construct for suspending a computation
provided by an implementation of `std::future::IntoFuture` until the given
future is ready to produce a value.
r[expr.await.construct]
The syntax for an await expression is an expression with a type that implements the [`IntoFuture`] trait, called the *future operand*, then the token `.`, and then the `await` keyword.
r[expr.await.allowed-positions]
Await expressions are legal only within an [async context], like an [`async fn`], [`async` closure], or [`async` block].
r[expr.await.effects]
More specifically, an await expression has the following effect.
1. Create a future by calling [`IntoFuture::into_future`] on the future operand.
2. Evaluate the future to a [future] `tmp`;
3. Pin `tmp` using [`Pin::new_unchecked`];
4. This pinned future is then polled by calling the [`Future::poll`] method and passing it the current [task context](#task-context);
5. If the call to `poll` returns [`Poll::Pending`], then the future returns `Poll::Pending`, suspending its state so that, when the surrounding async context is re-polled,execution returns to step 3;
6. Otherwise the call to `poll` must have returned [`Poll::Ready`], in which case the value contained in the [`Poll::Ready`] variant is used as the result of the `await` expression itself.
r[expr.await.edition2018]
> [!EDITION-2018]
> Await expressions are only available beginning with Rust 2018.
r[expr.await.task]
## Task context
The task context refers to the [`Context`] which was supplied to the current [async context] when the async context itself was polled.
Because `await` expressions are only legal in an async context, there must be some task context available.
r[expr.await.desugar]
## Approximate desugaring
Effectively, an await expression is roughly equivalent to the following non-normative desugaring:
<!-- ignore: example expansion -->
```rust,ignore
match operand.into_future() {
mut pinned => loop {
let mut pin = unsafe { Pin::new_unchecked(&mut pinned) };
match Pin::future::poll(Pin::borrow(&mut pin), &mut current_context) {
Poll::Ready(r) => break r,
Poll::Pending => yield Poll::Pending,
}
}
}
```
where the `yield` pseudo-code returns `Poll::Pending` and, when re-invoked, resumes execution from that point.
The variable `current_context` refers to the context taken from the async environment.
[`async fn`]: ../items/functions.md#async-functions
[`async` closure]: closure-expr.md#async-closures
[`async` block]: block-expr.md#async-blocks
[`Context`]: std::task::Context
[`future::poll`]: std::future::Future::poll
[`pin::new_unchecked`]: std::pin::Pin::new_unchecked
[`poll::Pending`]: std::task::Poll::Pending
[`poll::Ready`]: std::task::Poll::Ready
[async context]: ../expressions/block-expr.md#async-context
[future]: std::future::Future
[`IntoFuture`]: std::future::IntoFuture
[`IntoFuture::into_future`]: std::future::IntoFuture::into_future