Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 605
async-await initial reference material#635
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Uh oh!
There was an error while loading. Please reload this page.
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Jump to file
Failed to load files.
Loading
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| # Await expressions | ||
| > **<sup>Syntax</sup>**\ | ||
| > _AwaitExpression_ :\ | ||
| > [_Expression_] `.` `await` | ||
| Await expressions are legal only within an [async context], like an | ||
| [`async fn`] or an [`async` block]. They operate on a [future]. Their effect | ||
| is to suspend the current computation until the given future is ready | ||
| to produce a value. | ||
| More specifically, an `<expr>.await` expression has the following effect. | ||
| 1. Evaluate `<expr>` to a [future] `tmp`; | ||
| 2. Pin `tmp` using [`Pin::new_unchecked`]; | ||
| 3. This pinned future is then polled by calling the [`Future::poll`] method and | ||
| passing it the current [task context](#task-context); | ||
| 3. 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 | ||
| 2; | ||
| 4. 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. | ||
| [`async fn`]: ../items/functions.md#async-functions | ||
| [`async` block]: block-expr.md#async-blocks | ||
| [future]: ../../std/future/trait.Future.html | ||
| [_Expression_]: ../expressions.md | ||
| [`Future::poll`]: ../../std/future/trait.Future.html#tymethod.poll | ||
| [`Context`]: ../../std/task/struct.Context.html | ||
| [`Pin::new_unchecked`]: ../../std/pin/struct.Pin.html#method.new_unchecked | ||
| [`Poll::Pending`]: ../../std/task/enum.Poll.html#variant.Pending | ||
| [`Poll::Ready`]: ../../std/task/enum.Poll.html#variant.Ready | ||
| > **Edition differences**: Await expressions are only available beginning with | ||
| > Rust 2018. | ||
| ## 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. | ||
| [`Context`]: ../../std/task/struct.Context.html | ||
| [async context]: ../expressions/block-expr.md#async-context | ||
| ## Approximate desugaring | ||
| Effectively, an `<expr>.await` expression is roughly | ||
| equivalent to the following (this desugaring is not normative): | ||
| ```rust,ignore | ||
| let future = /* <expr> */; | ||
| loop { | ||
| let mut pin = unsafe { Pin::new_unchecked(&mut future) }; | ||
| 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. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -8,7 +8,10 @@ | ||
| > [_BlockExpression_] | ||
| > | ||
| > _FunctionQualifiers_ :\ | ||
| > `const`<sup>?</sup> `unsafe`<sup>?</sup> (`extern` _Abi_<sup>?</sup>)<sup>?</sup> | ||
| > _AsyncConstQualifiers_<sup>?</sup> `unsafe`<sup>?</sup> (`extern` _Abi_<sup>?</sup>)<sup>?</sup> | ||
| > | ||
| > _AsyncConstQualifiers_ :\ | ||
| > `async` | `const` | ||
| > | ||
| > _Abi_ :\ | ||
| > [STRING_LITERAL] | [RAW_STRING_LITERAL] | ||
| @@ -189,6 +192,104 @@ Exhaustive list of permitted structures in const functions: | ||
| the following unsafe operations: | ||
| * calls to const unsafe functions | ||
| ## Async functions | ||
| Functions may be qualified as async, and this can also be combined with the | ||
| `unsafe` qualifier: | ||
| ```rust,edition2018 | ||
| async fn regular_example() { } | ||
| async unsafe fn unsafe_example() { } | ||
| ``` | ||
| Async functions do no work when called: instead, they | ||
| capture their arguments into a future. When polled, that future will | ||
| execute the function's body. | ||
| An async function is roughly equivalent to a function | ||
| that returns [`impl Future`] and with an [`async move` block][async-blocks] as | ||
| its body: | ||
| ```rust,edition2018 | ||
ehuss marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| // Source | ||
| async fn example(x: &str) -> usize { | ||
| x.len() | ||
| } | ||
| ``` | ||
| is roughly equivalent to: | ||
| ```rust,edition2018 | ||
| # use std::future::Future; | ||
| // Desugared | ||
| fn example<'a>(x: &'a str) -> impl Future<Output = usize> + 'a { | ||
| async move { x.len() } | ||
| } | ||
| ``` | ||
| The actual desugaring is more complex: | ||
| - The return type in the desugaring is assumed to capture all lifetime | ||
| parameters from the `async fn` declaration. This can be seen in the | ||
| desugared example above, which explicitly outlives, and hence | ||
| captures, `'a`. | ||
| - The [`async move` block][async-blocks] in the body captures all function | ||
| parameters, including those that are unused or bound to a `_` | ||
| pattern. This ensures that function parameters are dropped in the | ||
| same order as they would be if the function were not async, except | ||
| that the drop occurs when the returned future has been fully | ||
| awaited. | ||
| For more information on the effect of async, see [`async` blocks][async-blocks]. | ||
| [async-blocks]: ../expressions/block-expr.md#async-blocks | ||
| [`impl Future`]: ../types/impl-trait.md | ||
| > **Edition differences**: Async functions are only available beginning with | ||
| > Rust 2018. | ||
| ### Combining `async` and `unsafe` | ||
| It is legal to declare a function that is both async and unsafe. The | ||
| resulting function is unsafe to call and (like any async function) | ||
| returns a future. This future is just an ordinary future and thus an | ||
| `unsafe` context is not required to "await" it: | ||
| ```rust,edition2018 | ||
| // Returns a future that, when awaited, dereferences `x`. | ||
| // | ||
| // Soundness condition: `x` must be safe to dereference until | ||
| // the resulting future is complete. | ||
| async unsafe fn unsafe_example(x: *const i32) -> i32 { | ||
| *x | ||
| } | ||
| async fn safe_example() { | ||
| // An `unsafe` block is required to invoke the function initially: | ||
| let p = 22; | ||
| let future = unsafe { unsafe_example(&p) }; | ||
| // But no `unsafe` block required here. This will | ||
| // read the value of `p`: | ||
| let q = future.await; | ||
| } | ||
| ``` | ||
| Note that this behavior is a consequence of the desugaring to a | ||
| function that returns an `impl Future` -- in this case, the function | ||
| we desugar to is an `unsafe` function, but the return value remains | ||
| the same. | ||
| Unsafe is used on an async function in precisely the same way that it | ||
| is used on other functions: it indicates that the function imposes | ||
| some additional obligations on its caller to ensure soundness. As in any | ||
| other unsafe function, these conditions may extend beyond the initial | ||
| call itself -- in the snippet above, for example, the `unsafe_example` | ||
| function took a pointer `x` as argument, and then (when awaited) | ||
| dereferenced that pointer. This implies that `x` would have to be | ||
| valid until the future is finished executing, and it is the callers | ||
| responsibility to ensure that. | ||
| ## Attributes on functions | ||
| [Outer attributes][attributes] are allowed on functions. [Inner | ||
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.