genawaiter/rc/
mod.rs

1/*!
2This module implements a generator which stores its state on the heap.
3
4You can create a basic generator with [`gen!`] and [`yield_!`].
5
6[`gen!`]: macro.gen.html
7
8```rust
9# #[cfg(feature = "proc_macro")]
10# fn feature_gate() {
11# use genawaiter::{rc::gen, yield_};
12#
13let mut my_generator = gen!({
14    yield_!(10);
15});
16# my_generator.resume();
17# }
18```
19
20If you need to reuse logic between multiple generators, you can define the logic with
21[`rc_producer!`] and [`yield_!`], and instantiate generators with [`Gen::new`].
22
23```rust
24# #[cfg(feature = "proc_macro")]
25# fn feature_gate() {
26# use genawaiter::{rc::Gen, rc_producer as producer, yield_};
27#
28let my_producer = producer!({
29    yield_!(10);
30});
31let mut my_generator = Gen::new(my_producer);
32# my_generator.resume();
33# }
34```
35
36If you don't like macros, you can use the low-level API directly.
37
38```rust
39# use genawaiter::rc::{Co, Gen};
40#
41async fn my_producer(co: Co<u8>) {
42    co.yield_(10).await;
43}
44let mut my_generator = Gen::new(my_producer);
45# my_generator.resume();
46```
47
48# Examples
49
50## Using `Iterator`
51
52Generators implement `Iterator`, so you can use them in a for loop:
53
54```rust
55# #[cfg(feature = "proc_macro")]
56# fn feature_gate() {
57use genawaiter::{rc::gen, yield_};
58
59let odds_under_ten = gen!({
60    let mut n = 1;
61    while n < 10 {
62        yield_!(n);
63        n += 2;
64    }
65});
66
67# let mut test = Vec::new();
68for num in odds_under_ten {
69    println!("{}", num);
70    # test.push(num);
71}
72# assert_eq!(test, [1, 3, 5, 7, 9]);
73# }
74```
75
76## Collecting into a `Vec`
77
78```rust
79# #[cfg(feature = "proc_macro")]
80# fn feature_gate() {
81# use genawaiter::{rc::gen, yield_};
82#
83# let odds_under_ten = gen!({
84#     for n in (1..).step_by(2).take_while(|&n| n < 10) { yield_!(n); }
85# });
86#
87let xs: Vec<_> = odds_under_ten.into_iter().collect();
88assert_eq!(xs, [1, 3, 5, 7, 9]);
89# }
90```
91
92## A generator is a closure
93
94Like any closure, you can capture values from outer scopes.
95
96```rust
97# #[cfg(feature = "proc_macro")]
98# fn feature_gate() {
99# use genawaiter::{rc::gen, yield_, GeneratorState};
100#
101let two = 2;
102let mut multiply = gen!({
103    yield_!(10 * two);
104});
105assert_eq!(multiply.resume(), GeneratorState::Yielded(20));
106# }
107```
108
109## Using `resume()`
110
111```rust
112# #[cfg(feature = "proc_macro")]
113# fn feature_gate() {
114# use genawaiter::{rc::gen, yield_, GeneratorState};
115#
116# let mut odds_under_ten = gen!({
117#     for n in (1..).step_by(2).take_while(|&n| n < 10) { yield_!(n); }
118# });
119#
120assert_eq!(odds_under_ten.resume(), GeneratorState::Yielded(1));
121assert_eq!(odds_under_ten.resume(), GeneratorState::Yielded(3));
122assert_eq!(odds_under_ten.resume(), GeneratorState::Yielded(5));
123assert_eq!(odds_under_ten.resume(), GeneratorState::Yielded(7));
124assert_eq!(odds_under_ten.resume(), GeneratorState::Yielded(9));
125assert_eq!(odds_under_ten.resume(), GeneratorState::Complete(()));
126# }
127```
128
129## Passing resume arguments
130
131You can pass values into the generator.
132
133Note that the first resume argument will be lost. This is because at the time the first
134value is sent, there is no future being awaited inside the generator, so there is no
135place the value could go where the generator could observe it.
136
137```rust
138# #[cfg(feature = "proc_macro")]
139# fn feature_gate() {
140# use genawaiter::{rc::gen, yield_};
141#
142let mut check_numbers = gen!({
143    let num = yield_!(());
144    assert_eq!(num, 1);
145
146    let num = yield_!(());
147    assert_eq!(num, 2);
148});
149
150check_numbers.resume_with(0);
151check_numbers.resume_with(1);
152check_numbers.resume_with(2);
153# }
154```
155
156## Returning a completion value
157
158You can return a completion value with a different type than the values that are
159yielded.
160
161```rust
162# #[cfg(feature = "proc_macro")]
163# fn feature_gate() {
164# use genawaiter::{rc::gen, yield_, GeneratorState};
165#
166let mut numbers_then_string = gen!({
167    yield_!(10);
168    yield_!(20);
169    "done!"
170});
171
172assert_eq!(numbers_then_string.resume(), GeneratorState::Yielded(10));
173assert_eq!(numbers_then_string.resume(), GeneratorState::Yielded(20));
174assert_eq!(numbers_then_string.resume(), GeneratorState::Complete("done!"));
175# }
176```
177
178## Defining a reusable producer function
179
180```rust
181# #[cfg(feature = "proc_macro")]
182# fn feature_gate() {
183# use genawaiter::{rc::{producer_fn, Gen}, yield_, GeneratorState};
184#
185#[producer_fn(u8)]
186async fn produce() {
187    yield_!(10);
188}
189
190let mut gen = Gen::new(produce);
191assert_eq!(gen.resume(), GeneratorState::Yielded(10));
192# }
193```
194
195## Defining a reusable producer closure
196
197```rust
198# #[cfg(feature = "proc_macro")]
199# fn feature_gate() {
200# use genawaiter::{rc::Gen, yield_, GeneratorState};
201use genawaiter::rc_producer as producer;
202
203let produce = producer!({
204    yield_!(10);
205});
206
207let mut gen = Gen::new(produce);
208assert_eq!(gen.resume(), GeneratorState::Yielded(10));
209# }
210```
211
212## Using the low-level API
213
214You can define an `async fn` directly, instead of relying on the `gen!` or `producer!`
215macros.
216
217```rust
218use genawaiter::rc::{Co, Gen};
219
220async fn producer(co: Co<i32>) {
221    let mut n = 1;
222    while n < 10 {
223        co.yield_(n).await;
224        n += 2;
225    }
226}
227
228let odds_under_ten = Gen::new(producer);
229let result: Vec<_> = odds_under_ten.into_iter().collect();
230assert_eq!(result, [1, 3, 5, 7, 9]);
231```
232
233## Using the low-level API with an async closure (nightly Rust only)
234
235```ignore
236# use genawaiter::{rc::Gen, GeneratorState};
237#
238let gen = Gen::new(async move |co| {
239    co.yield_(10).await;
240    co.yield_(20).await;
241});
242assert_eq!(gen.resume(), GeneratorState::Yielded(10));
243assert_eq!(gen.resume(), GeneratorState::Yielded(20));
244assert_eq!(gen.resume(), GeneratorState::Complete(()));
245```
246
247## Using the low-level API with an async <del>closure</del> faux·sure (for stable Rust)
248
249```
250# use genawaiter::{rc::Gen, GeneratorState};
251#
252let mut gen = Gen::new(|co| async move {
253    co.yield_(10).await;
254    co.yield_(20).await;
255});
256assert_eq!(gen.resume(), GeneratorState::Yielded(10));
257assert_eq!(gen.resume(), GeneratorState::Yielded(20));
258assert_eq!(gen.resume(), GeneratorState::Complete(()));
259```
260
261## Using the low-level API with function arguments
262
263This is just ordinary Rust, nothing special.
264
265```rust
266# use genawaiter::{rc::{Co, Gen}, GeneratorState};
267#
268async fn multiples_of(num: i32, co: Co<i32>) {
269    let mut cur = num;
270    loop {
271        co.yield_(cur).await;
272        cur += num;
273    }
274}
275
276let mut gen = Gen::new(|co| multiples_of(10, co));
277assert_eq!(gen.resume(), GeneratorState::Yielded(10));
278assert_eq!(gen.resume(), GeneratorState::Yielded(20));
279assert_eq!(gen.resume(), GeneratorState::Yielded(30));
280```
281*/
282
283pub use crate::rc::{engine::Co, generator::Gen};
284
285/// Creates a generator.
286///
287/// This macro takes one argument, which is the body of the generator. It should
288/// contain one or more calls to the [`yield_!`] macro.
289///
290/// # Examples
291///
292/// [_See the module-level docs for examples._](.)
293#[cfg(feature = "proc_macro")]
294pub use genawaiter_macro::rc_gen as gen;
295
296/// Turns a function into a producer, which can then be used to create a
297/// generator.
298///
299/// The body of the function should contain one or more [`yield_!`] expressions.
300///
301/// # Examples
302///
303/// [_See the module-level docs for examples._](.)
304#[cfg(feature = "proc_macro")]
305pub use genawaiter_proc_macro::rc_producer_fn as producer_fn;
306
307mod engine;
308mod generator;
309mod iterator;
310#[cfg(feature = "futures03")]
311mod stream;
312
313#[cfg(feature = "nightly")]
314#[cfg(test)]
315mod nightly_tests;
316
317#[cfg(test)]
318mod tests {
319    use crate::{
320        rc::{Co, Gen},
321        testing::DummyFuture,
322        GeneratorState,
323    };
324    use std::{
325        cell::{Cell, RefCell},
326        future::Future,
327    };
328
329    async fn simple_producer(co: Co<i32>) -> &'static str {
330        co.yield_(10).await;
331        "done"
332    }
333
334    #[test]
335    fn function() {
336        let mut gen = Gen::new(simple_producer);
337        assert_eq!(gen.resume(), GeneratorState::Yielded(10));
338        assert_eq!(gen.resume(), GeneratorState::Complete("done"));
339    }
340
341    #[test]
342    fn simple_closure() {
343        async fn gen(i: i32, co: Co<i32>) -> &'static str {
344            co.yield_(i * 2).await;
345            "done"
346        }
347
348        let mut gen = Gen::new(|co| gen(5, co));
349        assert_eq!(gen.resume(), GeneratorState::Yielded(10));
350        assert_eq!(gen.resume(), GeneratorState::Complete("done"));
351    }
352
353    #[test]
354    fn resume_args() {
355        async fn gen(resumes: &RefCell<Vec<&str>>, co: Co<i32, &'static str>) {
356            let resume_arg = co.yield_(10).await;
357            resumes.borrow_mut().push(resume_arg);
358            let resume_arg = co.yield_(20).await;
359            resumes.borrow_mut().push(resume_arg);
360        }
361
362        let resumes = RefCell::new(Vec::new());
363        let mut gen = Gen::new(|co| gen(&resumes, co));
364        assert_eq!(*resumes.borrow(), &[] as &[&str]);
365
366        assert_eq!(gen.resume_with("ignored"), GeneratorState::Yielded(10));
367        assert_eq!(*resumes.borrow(), &[] as &[&str]);
368
369        assert_eq!(gen.resume_with("abc"), GeneratorState::Yielded(20));
370        assert_eq!(*resumes.borrow(), &["abc"]);
371
372        assert_eq!(gen.resume_with("def"), GeneratorState::Complete(()));
373        assert_eq!(*resumes.borrow(), &["abc", "def"]);
374    }
375
376    #[test]
377    #[should_panic(expected = "non-async method")]
378    fn forbidden_await_helpful_message() {
379        async fn wrong(_: Co<i32>) {
380            DummyFuture.await;
381        }
382
383        let mut gen = Gen::new(wrong);
384        gen.resume();
385    }
386
387    #[test]
388    #[should_panic(expected = "Co::yield_")]
389    fn multiple_yield_helpful_message() {
390        async fn wrong(co: Co<i32>) {
391            let _ = co.yield_(10);
392            let _ = co.yield_(20);
393        }
394
395        let mut gen = Gen::new(wrong);
396        gen.resume();
397    }
398
399    #[test]
400    #[should_panic = "should have been dropped by now"]
401    fn escaped_co_helpful_message() {
402        async fn shenanigans(co: Co<i32>) -> Co<i32> {
403            co
404        }
405
406        let mut gen = Gen::new(shenanigans);
407        let escaped_co = match gen.resume() {
408            GeneratorState::Yielded(_) => panic!(),
409            GeneratorState::Complete(co) => co,
410        };
411        let _ = escaped_co.yield_(10);
412    }
413
414    /// This tests in a roundabout way that the `Gen` object can be moved. This
415    /// should happen without moving the allocations inside so we don't
416    /// segfault.
417    #[test]
418    fn gen_is_movable() {
419        #[inline(never)]
420        async fn produce(addrs: &mut Vec<*const i32>, co: Co<i32>) -> &'static str {
421            let sentinel: Cell<i32> = Cell::new(0x8001);
422            // If the future state moved, this reference would become invalid, and
423            // hilarity would ensue.
424            let sentinel_ref: &Cell<i32> = &sentinel;
425
426            // Test a few times that `sentinel` and `sentinel_ref` point to the same
427            // data.
428
429            assert_eq!(sentinel.get(), 0x8001);
430            sentinel_ref.set(0x8002);
431            assert_eq!(sentinel.get(), 0x8002);
432            addrs.push(sentinel.as_ptr());
433
434            co.yield_(10).await;
435
436            assert_eq!(sentinel.get(), 0x8002);
437            sentinel_ref.set(0x8003);
438            assert_eq!(sentinel.get(), 0x8003);
439            addrs.push(sentinel.as_ptr());
440
441            co.yield_(20).await;
442
443            assert_eq!(sentinel.get(), 0x8003);
444            sentinel_ref.set(0x8004);
445            assert_eq!(sentinel.get(), 0x8004);
446            addrs.push(sentinel.as_ptr());
447
448            "done"
449        }
450
451        /// Create a generator, resume it once (so `sentinel_ref` gets
452        /// initialized), and then move it out of the function.
453        fn create_generator(
454            addrs: &mut Vec<*const i32>,
455        ) -> Gen<i32, (), impl Future<Output = &'static str> + '_> {
456            let mut gen = Gen::new(move |co| produce(addrs, co));
457            assert_eq!(gen.resume(), GeneratorState::Yielded(10));
458            gen
459        }
460
461        let mut addrs = Vec::new();
462        let mut gen = create_generator(&mut addrs);
463
464        assert_eq!(gen.resume(), GeneratorState::Yielded(20));
465        assert_eq!(gen.resume(), GeneratorState::Complete("done"));
466        drop(gen);
467
468        assert!(addrs.iter().all(|&p| p == addrs[0]));
469    }
470}