]> git.lizzy.rs Git - rust.git/blob - src/doc/unstable-book/src/language-features/generators.md
Rollup merge of #48270 - leodasvacas:refactor-casts, r=nikomatsakis
[rust.git] / src / doc / unstable-book / src / language-features / generators.md
1 # `generators`
2
3 The tracking issue for this feature is: [#43122]
4
5 [#43122]: https://github.com/rust-lang/rust/issues/43122
6
7 ------------------------
8
9 The `generators` feature gate in Rust allows you to define generator or
10 coroutine literals. A generator is a "resumable function" that syntactically
11 resembles a closure but compiles to much different semantics in the compiler
12 itself. The primary feature of a generator is that it can be suspended during
13 execution to be resumed at a later date. Generators use the `yield` keyword to
14 "return", and then the caller can `resume` a generator to resume execution just
15 after the `yield` keyword.
16
17 Generators are an extra-unstable feature in the compiler right now. Added in
18 [RFC 2033] they're mostly intended right now as a information/constraint
19 gathering phase. The intent is that experimentation can happen on the nightly
20 compiler before actual stabilization. A further RFC will be required to
21 stabilize generators/coroutines and will likely contain at least a few small
22 tweaks to the overall design.
23
24 [RFC 2033]: https://github.com/rust-lang/rfcs/pull/2033
25
26 A syntactical example of a generator is:
27
28 ```rust
29 #![feature(generators, generator_trait)]
30
31 use std::ops::{Generator, GeneratorState};
32
33 fn main() {
34     let mut generator = || {
35         yield 1;
36         return "foo"
37     };
38
39     match unsafe { generator.resume() } {
40         GeneratorState::Yielded(1) => {}
41         _ => panic!("unexpected value from resume"),
42     }
43     match unsafe { generator.resume() } {
44         GeneratorState::Complete("foo") => {}
45         _ => panic!("unexpected value from resume"),
46     }
47 }
48 ```
49
50 Generators are closure-like literals which can contain a `yield` statement. The
51 `yield` statement takes an optional expression of a value to yield out of the
52 generator. All generator literals implement the `Generator` trait in the
53 `std::ops` module. The `Generator` trait has one main method, `resume`, which
54 resumes execution of the generator at the previous suspension point.
55
56 An example of the control flow of generators is that the following example
57 prints all numbers in order:
58
59 ```rust
60 #![feature(generators, generator_trait)]
61
62 use std::ops::Generator;
63
64 fn main() {
65     let mut generator = || {
66         println!("2");
67         yield;
68         println!("4");
69     };
70
71     println!("1");
72     unsafe { generator.resume() };
73     println!("3");
74     unsafe { generator.resume() };
75     println!("5");
76 }
77 ```
78
79 At this time the main intended use case of generators is an implementation
80 primitive for async/await syntax, but generators will likely be extended to
81 ergonomic implementations of iterators and other primitives in the future.
82 Feedback on the design and usage is always appreciated!
83
84 ### The `Generator` trait
85
86 The `Generator` trait in `std::ops` currently looks like:
87
88 ```
89 # #![feature(generator_trait)]
90 # use std::ops::GeneratorState;
91
92 pub trait Generator {
93     type Yield;
94     type Return;
95     unsafe fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return>;
96 }
97 ```
98
99 The `Generator::Yield` type is the type of values that can be yielded with the
100 `yield` statement. The `Generator::Return` type is the returned type of the
101 generator. This is typically the last expression in a generator's definition or
102 any value passed to `return` in a generator. The `resume` function is the entry
103 point for executing the `Generator` itself.
104
105 The return value of `resume`, `GeneratorState`, looks like:
106
107 ```
108 pub enum GeneratorState<Y, R> {
109     Yielded(Y),
110     Complete(R),
111 }
112 ```
113
114 The `Yielded` variant indicates that the generator can later be resumed. This
115 corresponds to a `yield` point in a generator. The `Complete` variant indicates
116 that the generator is complete and cannot be resumed again. Calling `resume`
117 after a generator has returned `Complete` will likely result in a panic of the
118 program.
119
120 ### Closure-like semantics
121
122 The closure-like syntax for generators alludes to the fact that they also have
123 closure-like semantics. Namely:
124
125 * When created, a generator executes no code. A closure literal does not
126   actually execute any of the closure's code on construction, and similarly a
127   generator literal does not execute any code inside the generator when
128   constructed.
129
130 * Generators can capture outer variables by reference or by move, and this can
131   be tweaked with the `move` keyword at the beginning of the closure. Like
132   closures all generators will have an implicit environment which is inferred by
133   the compiler. Outer variables can be moved into a generator for use as the
134   generator progresses.
135
136 * Generator literals produce a value with a unique type which implements the
137   `std::ops::Generator` trait. This allows actual execution of the generator
138   through the `Generator::resume` method as well as also naming it in return
139   types and such.
140
141 * Traits like `Send` and `Sync` are automatically implemented for a `Generator`
142   depending on the captured variables of the environment. Unlike closures,
143   generators also depend on variables live across suspension points. This means
144   that although the ambient environment may be `Send` or `Sync`, the generator
145   itself may not be due to internal variables live across `yield` points being
146   not-`Send` or not-`Sync`. Note that generators, like closures, do
147   not implement traits like `Copy` or `Clone` automatically.
148
149 * Whenever a generator is dropped it will drop all captured environment
150   variables.
151
152 Note that unlike closures generators at this time cannot take any arguments.
153 That is, generators must always look like `|| { ... }`. This restriction may be
154 lifted at a future date, the design is ongoing!
155
156 ### Generators as state machines
157
158 In the compiler, generators are currently compiled as state machines. Each
159 `yield` expression will correspond to a different state that stores all live
160 variables over that suspension point. Resumption of a generator will dispatch on
161 the current state and then execute internally until a `yield` is reached, at
162 which point all state is saved off in the generator and a value is returned.
163
164 Let's take a look at an example to see what's going on here:
165
166 ```rust
167 #![feature(generators, generator_trait)]
168
169 use std::ops::Generator;
170
171 fn main() {
172     let ret = "foo";
173     let mut generator = move || {
174         yield 1;
175         return ret
176     };
177
178     unsafe { generator.resume() };
179     unsafe { generator.resume() };
180 }
181 ```
182
183 This generator literal will compile down to something similar to:
184
185 ```rust
186 #![feature(generators, generator_trait)]
187
188 use std::ops::{Generator, GeneratorState};
189
190 fn main() {
191     let ret = "foo";
192     let mut generator = {
193         enum __Generator {
194             Start(&'static str),
195             Yield1(&'static str),
196             Done,
197         }
198
199         impl Generator for __Generator {
200             type Yield = i32;
201             type Return = &'static str;
202
203             unsafe fn resume(&mut self) -> GeneratorState<i32, &'static str> {
204                 use std::mem;
205                 match mem::replace(self, __Generator::Done) {
206                     __Generator::Start(s) => {
207                         *self = __Generator::Yield1(s);
208                         GeneratorState::Yielded(1)
209                     }
210
211                     __Generator::Yield1(s) => {
212                         *self = __Generator::Done;
213                         GeneratorState::Complete(s)
214                     }
215
216                     __Generator::Done => {
217                         panic!("generator resumed after completion")
218                     }
219                 }
220             }
221         }
222
223         __Generator::Start(ret)
224     };
225
226     unsafe { generator.resume() };
227     unsafe { generator.resume() };
228 }
229 ```
230
231 Notably here we can see that the compiler is generating a fresh type,
232 `__Generator` in this case. This type has a number of states (represented here
233 as an `enum`) corresponding to each of the conceptual states of the generator.
234 At the beginning we're closing over our outer variable `foo` and then that
235 variable is also live over the `yield` point, so it's stored in both states.
236
237 When the generator starts it'll immediately yield 1, but it saves off its state
238 just before it does so indicating that it has reached the yield point. Upon
239 resuming again we'll execute the `return ret` which returns the `Complete`
240 state.
241
242 Here we can also note that the `Done` state, if resumed, panics immediately as
243 it's invalid to resume a completed generator. It's also worth noting that this
244 is just a rough desugaring, not a normative specification for what the compiler
245 does.