[−][src]Module genawaiter::rc
This module implements a generator which stores its state on the heap.
You can create a generator with [Gen::new
][rc::Gen::new
]. Pass it a function that
bootstraps the generator.
Values can be yielded from the generator by calling [Co::yield_
][rc::Co::yield_
],
and immediately awaiting the future it returns:
co.yield_("value").await;
You can get values out of the generator in either of two ways:
- Treat it as an iterator. In this case, the future's output must be
()
. - Call
resume()
until it completes. In this case, the future's output can be anything, and it will be returned in the finalGeneratorState::Complete
.
These generators are memory-safe no matter what you do, but some operations are left unspecified. You can avoid unspecified behavior by not doing silly things. Here is a non-exhaustive list of silly things:
- Whenever calling
yield_()
, always immediately await its result. - Do not
await
any futures other than ones returned byCo::yield_
. - Do not let the
Co
object escape the scope of the generator. Once the starting future returnsPoll::Ready
, theCo
object should already have been dropped.
Examples
(See the crate-level docs for the definition of odd_numbers_less_than_ten
.)
Using Iterator
Generators implement Iterator
, so you can use them in a for loop:
for n in Gen::new(odd_numbers_less_than_ten) { println!("{}", n); }
Collecting into a Vec
let gen = Gen::new(odd_numbers_less_than_ten); let xs: Vec<_> = gen.into_iter().collect(); assert_eq!(xs, [1, 3, 5, 7, 9]);
Using resume()
let mut gen = Gen::new(odd_numbers_less_than_ten); assert_eq!(gen.resume(), GeneratorState::Yielded(1)); assert_eq!(gen.resume(), GeneratorState::Yielded(3)); assert_eq!(gen.resume(), GeneratorState::Yielded(5)); assert_eq!(gen.resume(), GeneratorState::Yielded(7)); assert_eq!(gen.resume(), GeneratorState::Yielded(9)); assert_eq!(gen.resume(), GeneratorState::Complete(()));
Using an async closure (nightly only)
let mut gen = Gen::new(async move |co| { co.yield_(10).await; co.yield_(20).await; }); assert_eq!(gen.resume(), GeneratorState::Yielded(10)); assert_eq!(gen.resume(), GeneratorState::Yielded(20)); assert_eq!(gen.resume(), GeneratorState::Complete(()));
Passing arguments
This is just ordinary Rust, nothing special.
async fn multiples_of(num: i32, co: Co<i32>) { let mut cur = num; loop { co.yield_(cur).await; cur += num; } } let mut gen = Gen::new(|co| multiples_of(10, co)); assert_eq!(gen.resume(), GeneratorState::Yielded(10)); assert_eq!(gen.resume(), GeneratorState::Yielded(20)); assert_eq!(gen.resume(), GeneratorState::Yielded(30));
Returning a final value
You can return a final value with a different type than the values that are yielded.
async fn numbers_then_string(co: Co<i32>) -> &'static str { co.yield_(10).await; co.yield_(20).await; "done!" } let mut gen = Gen::new(numbers_then_string); assert_eq!(gen.resume(), GeneratorState::Yielded(10)); assert_eq!(gen.resume(), GeneratorState::Yielded(20)); assert_eq!(gen.resume(), GeneratorState::Complete("done!"));
Structs
Co | This object lets you yield values from the generator by calling the |
Gen | This is a generator which stores its state on the heap. |