[][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 final GeneratorState::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 by Co::yield_.
  • Do not let the Co object escape the scope of the generator. Once the starting future returns Poll::Ready, the Co 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)

This example deliberately fails to compile
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 yield_ method.

Gen

This is a generator which stores its state on the heap.