Skip to content

Commit e0b5db6

Browse files
committed
async-await reference material (squashed)
1 parent d191a0c commit e0b5db6

File tree

5 files changed

+243
-1
lines changed

5 files changed

+243
-1
lines changed

src/SUMMARY.md

+1
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
- [If and if let expressions](expressions/if-expr.md)
6868
- [Match expressions](expressions/match-expr.md)
6969
- [Return expressions](expressions/return-expr.md)
70+
- [Await expressions](expressions/await-expr.md)
7071

7172
- [Patterns](patterns.md)
7273

src/expressions.md

+4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
>       | [_OperatorExpression_]\
1414
>       | [_GroupedExpression_]\
1515
>       | [_ArrayExpression_]\
16+
>       | [_AwaitExpression_]\
1617
>       | [_IndexExpression_]\
1718
>       | [_TupleExpression_]\
1819
>       | [_TupleIndexingExpression_]\
@@ -33,6 +34,7 @@
3334
> &nbsp;&nbsp; [_OuterAttribute_]<sup>\*</sup>[](#expression-attributes)\
3435
> &nbsp;&nbsp; (\
3536
> &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; [_BlockExpression_]\
37+
> &nbsp;&nbsp; &nbsp;&nbsp; | [_AsyncBlockExpression_]\
3638
> &nbsp;&nbsp; &nbsp;&nbsp; | [_UnsafeBlockExpression_]\
3739
> &nbsp;&nbsp; &nbsp;&nbsp; | [_LoopExpression_]\
3840
> &nbsp;&nbsp; &nbsp;&nbsp; | [_IfExpression_]\
@@ -324,6 +326,8 @@ They are never allowed before:
324326

325327
[_ArithmeticOrLogicalExpression_]: expressions/operator-expr.md#arithmetic-and-logical-binary-operators
326328
[_ArrayExpression_]: expressions/array-expr.md
329+
[_AsyncBlockExpression_]: expressions/block-expr.md#async-blocks
330+
[_AwaitExpression_]: expressions/await-expr.md
327331
[_AssignmentExpression_]: expressions/operator-expr.md#assignment-expressions
328332
[_BlockExpression_]: expressions/block-expr.md
329333
[_BreakExpression_]: expressions/loop-expr.md#break-expressions

src/expressions/await-expr.md

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# Await expressions
2+
3+
> **<sup>Syntax</sup>**\
4+
> _AwaitExpression_ :\
5+
> &nbsp;&nbsp; [_Expression_] `.` `await`
6+
7+
Await expressions are legal only within an [async context], like an
8+
[`async fn`] or an [`async` block]. They operate on a [future]. Their effect
9+
is to suspend the current computation until the given future is ready
10+
to produce a value.
11+
12+
More specifically, an `<expr>.await` expression has the following effect.
13+
14+
1. Evaluate `<expr>` to a [future] `tmp`;
15+
2. Pin `tmp` using [`Pin::new_unchecked`];
16+
3. This pinned future is then polled by calling the [`Future::poll`] method and
17+
passing it the current [task context](#task-context);
18+
3. If the call to `poll` returns [`Poll::Pending`], then the future
19+
returns `Poll::Pending`, suspending its state so that, when the
20+
surrounding async context is re-polled, execution returns to step
21+
2;
22+
4. Otherwise the call to `poll` must have returned [`Poll::Ready`], in which case the
23+
value contained in the [`Poll::Ready`] variant is used as the result
24+
of the `await` expression itself.
25+
26+
[`async fn`]: ../items/functions.md#async-functions
27+
[`async` block]: block-expr.md#async-blocks
28+
[future]: ../../std/future/trait.Future.html
29+
[_Expression_]: ../expressions.md
30+
[`Future::poll`]: ../../std/future/trait.Future.html#tymethod.poll
31+
[`Context`]: ../../std/task/struct.Context.html
32+
[`Pin::new_unchecked`]: ../../std/pin/struct.Pin.html#method.new_unchecked
33+
[`Poll::Pending`]: ../../std/task/enum.Poll.html#variant.Pending
34+
[`Poll::Ready`]: ../../std/task/enum.Poll.html#variant.Ready
35+
36+
> **Edition differences**: Await expressions are only available beginning with
37+
> Rust 2018.
38+
39+
## Task context
40+
41+
The task context refers to the [`Context`] which was supplied to the
42+
current [async context] when the async context itself was
43+
polled. Because `await` expressions are only legal in an async
44+
context, there must be some task context available.
45+
46+
[`Context`]: ../../std/task/struct.Context.html
47+
[async context]: ../expressions/block-expr.md#async-context
48+
49+
## Approximate desugaring
50+
51+
Effectively, an `<expr>.await` expression is roughly
52+
equivalent to the following (this desugaring is not normative):
53+
54+
```rust,ignore
55+
let future = /* <expr> */;
56+
loop {
57+
let mut pin = unsafe { Pin::new_unchecked(&mut future) };
58+
match Pin::future::poll(Pin::borrow(&mut pin), &mut current_context) {
59+
Poll::Ready(r) => break r,
60+
Poll::Pending => yield Poll::Pending,
61+
}
62+
}
63+
```
64+
65+
where the `yield` pseudo-code returns `Poll::Pending` and, when
66+
re-invoked, resumes execution from that point. The variable
67+
`current_context` refers to the context taken from the async
68+
environment.

src/expressions/block-expr.md

+68
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,74 @@ fn move_by_block_expression() {
8080
}
8181
```
8282

83+
## `async` blocks
84+
85+
> **<sup>Syntax</sup>**\
86+
> _AsyncBlockExpression_ :\
87+
> &nbsp;&nbsp; `async` `move`<sup>?</sup> _BlockExpression_
88+
89+
An *async block* is a variant of a block expression which evaluates to
90+
a *future*. The final expression of the block, if present, determines
91+
the result value of the future.
92+
93+
Executing an async block is similar to executing a closure expression:
94+
its immediate effect is to produce and return an anonymous type.
95+
Whereas closures return a type that implements one or more of the
96+
[`std::ops::Fn`] traits, however, the type returned for an async block
97+
implements the [`std::future::Future`] trait. The actual data format for
98+
this type is unspecified.
99+
100+
> **Note:** The future type that rustc generates is roughly equivalent
101+
> to an enum with one variant per `await` point, where each variant
102+
> stores the data needed to resume from its corresponding point.
103+
104+
> **Edition differences**: Async blocks are only available beginning with Rust 2018.
105+
106+
[`std::ops::Fn`]: ../../std/ops/trait.Fn.html
107+
[`std::future::Future`]: ../../std/future/trait.Future.html
108+
109+
### Capture modes
110+
111+
Async blocks capture variables from their environment using the same
112+
[capture modes] as closures. Like closures, when written `async {
113+
.. }` the capture mode for each variable will be inferred from the
114+
content of the block. `async move { .. }` blocks however will move all
115+
referenced variables into the resulting future.
116+
117+
[capture modes]: ../types/closure.md#capture-modes
118+
[shared references]: ../types/pointer.md#shared-references-
119+
[mutable reference]: ../types/pointer.md#mutables-references-
120+
121+
### Async context
122+
123+
Because async blocks construct a future, they define an **async
124+
context** which can in turn contain [`await` expressions]. Async
125+
contexts are established by async blocks as well as the bodies of
126+
async functions, whose semantics are defined in terms of async blocks.
127+
128+
[`await` expressions]: await-expr.md
129+
130+
### Control-flow operators
131+
132+
Async blocks act like a function boundary, much like
133+
closures. Therefore, the `?` operator and `return` expressions both
134+
affect the output of the future, not the enclosing function or other
135+
context. That is, `return <expr>` from within a closure will return
136+
the result of `<expr>` as the output of the future. Similarly, if
137+
`<expr>?` propagates an error, that error is propagated as the result
138+
of the future.
139+
140+
Finally, the `break` and `continue` keywords cannot be used to branch
141+
out from an async block. Therefore the following is illegal:
142+
143+
```rust,edition2018,compile_fail
144+
loop {
145+
async move {
146+
break; // This would break out of the loop.
147+
}
148+
}
149+
```
150+
83151
## `unsafe` blocks
84152

85153
> **<sup>Syntax</sup>**\

src/items/functions.md

+102-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@
88
> &nbsp;&nbsp; &nbsp;&nbsp; [_BlockExpression_]
99
>
1010
> _FunctionQualifiers_ :\
11-
> &nbsp;&nbsp; `const`<sup>?</sup> `unsafe`<sup>?</sup> (`extern` _Abi_<sup>?</sup>)<sup>?</sup>
11+
> &nbsp;&nbsp; _AsyncConstQualifiers_<sup>?</sup> `unsafe`<sup>?</sup> (`extern` _Abi_<sup>?</sup>)<sup>?</sup>
12+
>
13+
> _AsyncConstQualifiers_ :\
14+
> &nbsp;&nbsp; `async` | `const`
1215
>
1316
> _Abi_ :\
1417
> &nbsp;&nbsp; [STRING_LITERAL] | [RAW_STRING_LITERAL]
@@ -189,6 +192,104 @@ Exhaustive list of permitted structures in const functions:
189192
the following unsafe operations:
190193
* calls to const unsafe functions
191194

195+
## Async functions
196+
197+
Functions may be qualified as async, and this can also be combined with the
198+
`unsafe` qualifier:
199+
200+
```rust,edition2018
201+
async fn regular_example() { }
202+
async unsafe fn unsafe_example() { }
203+
```
204+
205+
Async functions do no work when called: instead, they
206+
capture their arguments into a future. When polled, that future will
207+
execute the function's body.
208+
209+
An async function is roughly equivalent to a function
210+
that returns [`impl Future`] and with an [`async move` block][async-blocks] as
211+
its body:
212+
213+
```rust,edition2018
214+
// Source
215+
async fn example(x: &str) -> usize {
216+
x.len()
217+
}
218+
```
219+
220+
is roughly equivalent to:
221+
222+
```rust,edition2018
223+
# use std::future::Future;
224+
// Desugared
225+
fn example<'a>(x: &'a str) -> impl Future<Output = usize> + 'a {
226+
async move { x.len() }
227+
}
228+
```
229+
230+
The actual desugaring is more complex:
231+
232+
- The return type in the desugaring is assumed to capture all lifetime
233+
parameters from the `async fn` declaration. This can be seen in the
234+
desugared example above, which explicitly outlives, and hence
235+
captures, `'a`.
236+
- The [`async move` block][async-blocks] in the body captures all function
237+
parameters, including those that are unused or bound to a `_`
238+
pattern. This ensures that function parameters are dropped in the
239+
same order as they would be if the function were not async, except
240+
that the drop occurs when the returned future has been fully
241+
awaited.
242+
243+
For more information on the effect of async, see [`async` blocks][async-blocks].
244+
245+
[async-blocks]: ../expressions/block-expr.md#async-blocks
246+
[`impl Future`]: ../types/impl-trait.md
247+
248+
> **Edition differences**: Async functions are only available beginning with
249+
> Rust 2018.
250+
251+
### Combining `async` and `unsafe`
252+
253+
It is legal to declare a function that is both async and unsafe. The
254+
resulting function is unsafe to call and (like any async function)
255+
returns a future. This future is just an ordinary future and thus an
256+
`unsafe` context is not required to "await" it:
257+
258+
```rust,edition2018
259+
// Returns a future that, when awaited, dereferences `x`.
260+
//
261+
// Soundness condition: `x` must be safe to dereference until
262+
// the resulting future is complete.
263+
async unsafe fn unsafe_example(x: *const i32) -> i32 {
264+
*x
265+
}
266+
267+
async fn safe_example() {
268+
// An `unsafe` block is required to invoke the function initially:
269+
let p = 22;
270+
let future = unsafe { unsafe_example(&p) };
271+
272+
// But no `unsafe` block required here. This will
273+
// read the value of `p`:
274+
let q = future.await;
275+
}
276+
```
277+
278+
Note that this behavior is a consequence of the desugaring to a
279+
function that returns an `impl Future` -- in this case, the function
280+
we desugar to is an `unsafe` function, but the return value remains
281+
the same.
282+
283+
Unsafe is used on an async function in precisely the same way that it
284+
is used on other functions: it indicates that the function imposes
285+
some additional obligations on its caller to ensure soundness. As in any
286+
other unsafe function, these conditions may extend beyond the initial
287+
call itself -- in the snippet above, for example, the `unsafe_example`
288+
function took a pointer `x` as argument, and then (when awaited)
289+
dereferenced that pointer. This implies that `x` would have to be
290+
valid until the future is finished executing, and it is the callers
291+
responsibility to ensure that.
292+
192293
## Attributes on functions
193294

194295
[Outer attributes][attributes] are allowed on functions. [Inner

0 commit comments

Comments
 (0)