1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
/*!
This crate implements generators for Rust. Generators are a feature common across many
programming language. They let you yield a sequence of values from a function. A few
common use cases are:

- Easily building iterators.
- Avoiding allocating a list for a function which returns multiple values.

Rust has this feature too, but it is currently unstable (and thus nightly-only). But
with this crate, you can use them on stable Rust!

# Features

This crate has these features:

- `futures03` (disabled by default) – Implements `Stream` for all generator types.
  Adds a dependency on `futures-core`.
- `proc_macro` (enabled by default) – Adds support for macros, and adds various
  compile-time dependencies.

# Choose your guarantees

This crate supplies three concrete implementations of generators:

1. [`genawaiter::stack`](stack) – Allocation-free. You should prefer this when possible.

2. [`genawaiter::rc`](rc) – This allocates.

3. [`genawaiter::sync`](sync) – This allocates, and can be shared between threads.

   [unus]: https://github.com/whatisaphone/genawaiter/blob/4a2b185/src/waker.rs#L9
   [duo]: https://github.com/whatisaphone/genawaiter/blob/4a2b185/src/rc/engine.rs#L26

Here are the differences in table form:

|                                       | [`stack::Gen`] | [`rc::Gen`] | [`sync::Gen`] |
|---------------------------------------|----------------|-------------|---------------|
| Allocations per generator            | 0               | 2           | 2             |
| Generator can be moved after created | no              | yes         | yes           |
| Thread-safe                          | no              | no          | yes           |

# Creating a generator

Once you've chosen how and whether to allocate (see previous section), you can create a
generator using a macro from the `gen` family:

- [`stack::let_gen!`](stack/macro.let_gen.html)
- [`rc::gen!`](rc/macro.gen.html)
- [`sync::gen!`](sync/macro.gen.html)

```rust
# #[cfg(feature = "proc_macro")]
# fn feature_gate() {
# use genawaiter::{sync::gen, yield_};
#
let count_to_ten = gen!({
    for n in 0..10 {
        yield_!(n);
    }
});

# let result: Vec<_> = count_to_ten.into_iter().collect();
# assert_eq!(result, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
# }
```

To re-use logic between multiple generators, you can use a macro from the `producer`
family, and then pass the producer to `Gen::new`.

- [`stack_producer!`] and [`let_gen_using!`](stack/macro.let_gen_using.html)
- [`rc_producer!`] and [`Gen::new`](rc::Gen::new)
- [`sync_producer!`] and [`Gen::new`](sync::Gen::new)

```rust
# #[cfg(feature = "proc_macro")]
# fn feature_gate() {
# use genawaiter::{sync::Gen, sync_producer as producer, yield_};
#
let count_producer = producer!({
    for n in 0..10 {
        yield_!(n);
    }
});

let count_to_ten = Gen::new(count_producer);

# let result: Vec<_> = count_to_ten.into_iter().collect();
# assert_eq!(result, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
# }
```

If neither of these offers enough control for you, you can always skip the macros and
use the low-level API directly:

```rust
# use genawaiter::sync::{Co, Gen};
#
let count_to_ten = Gen::new(|co| async move {
    for n in 0..10 {
        co.yield_(n).await;
    }
});

# let result: Vec<_> = count_to_ten.into_iter().collect();
# assert_eq!(result, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
```

# A tale of three types

A generator can control the flow of up to three types of data:

- **Yield** – Each time a generator suspends execution, it can produce a value.
- **Resume** – Each time a generator is resumed, a value can be passed in.
- **Completion** – When a generator completes, it can produce one final value.

## Yield

Values can be yielded from the generator by calling `yield_`, and immediately awaiting
the future it returns. You can get these values out of the generator in either of two
ways:

- Call `resume()` or `resume_with()`. The values will be returned in a
  `GeneratorState::Yielded`.

  ```rust
  # #[cfg(feature = "proc_macro")]
  # fn feature_gate() {
  # use genawaiter::{sync::gen, yield_, GeneratorState};
  #
  let mut generator = gen!({
      yield_!(10);
  });
  let ten = generator.resume();
  assert_eq!(ten, GeneratorState::Yielded(10));
  # }
  ```

- Treat it as an iterator. For this to work, both the resume and completion types must
  be `()` .

  ```rust
  # #[cfg(feature = "proc_macro")]
  # fn feature_gate() {
  # use genawaiter::{sync::gen, yield_};
  #
  let generator = gen!({
      yield_!(10);
  });
  let xs: Vec<_> = generator.into_iter().collect();
  assert_eq!(xs, [10]);
  # }
  ```

## Resume

You can also send values back into the generator, by using `resume_with`. The generator
receives them from the future returned by `yield_`.

```rust
# #[cfg(feature = "proc_macro")]
# fn feature_gate() {
# use genawaiter::{sync::gen, yield_};
#
let mut printer = gen!({
    loop {
        let string = yield_!(());
        println!("{}", string);
    }
});
printer.resume_with("hello");
printer.resume_with("world");
# }
```

## Completion

A generator can produce one final value upon completion, by returning it from the
function. The consumer will receive this value as a `GeneratorState::Complete`.

```rust
# #[cfg(feature = "proc_macro")]
# fn feature_gate() {
# use genawaiter::{sync::gen, yield_, GeneratorState};
#
let mut generator = gen!({
    yield_!(10);
    "done"
});
assert_eq!(generator.resume(), GeneratorState::Yielded(10));
assert_eq!(generator.resume(), GeneratorState::Complete("done"));
# }
```

# Async generators

If you await other futures inside the generator, it becomes an _async generator_. It
does not makes sense to treat an async generator as an `Iterable`, since you cannot
`await` an `Iterable`. Instead, you can treat it as a `Stream`. This requires opting in
to the dependency on `futures` with the `futures03` feature.

```toml
[dependencies]
genawaiter = { version = "...", features = ["futures03"] }
```

```rust
# #[cfg(all(feature = "proc_macro", feature = "futures03"))]
# fn feature_gate() {
# use futures::executor::block_on_stream;
# use genawaiter::{sync::gen, yield_};
#
async fn async_one() -> i32 { 1 }
async fn async_two() -> i32 { 2 }

let gen = gen!({
    let one = async_one().await;
    yield_!(one);
    let two = async_two().await;
    yield_!(two);
});
let stream = block_on_stream(gen);
let items: Vec<_> = stream.collect();
assert_eq!(items, [1, 2]);
# }
```

Async generators also provide a `async_resume` method for lower-level control. (This
works even without the `futures03` feature.)

```rust
# #[cfg(feature = "proc_macro")]
# async fn feature_gate() {
# use genawaiter::{sync::gen, yield_, GeneratorState};
# use std::task::Poll;
#
# let mut gen = gen!({
#     yield_!(10);
# });
#
match gen.async_resume().await {
    GeneratorState::Yielded(_) => {}
    GeneratorState::Complete(_) => {}
}
# }
```

# Backported stdlib types

This crate supplies [`Generator`](trait.Generator.html) and
[`GeneratorState`](enum.GeneratorState.html). They are copy/pasted from the stdlib (with
stability attributes removed) so they can be used on stable Rust. If/when real
generators are stabilized, hopefully they would be drop-in replacements. Javascript
developers might recognize this as a polyfill.

There is also a [`Coroutine`](trait.Coroutine.html) trait, which does not come from the
stdlib. A `Coroutine` is a generalization of a `Generator`. A `Generator` constrains the
resume argument type to `()`, but in a `Coroutine` it can be anything.
*/

#![cfg_attr(feature = "nightly", feature(async_closure))]
#![warn(future_incompatible, rust_2018_compatibility, rust_2018_idioms, unused)]
#![warn(missing_docs, clippy::cargo, clippy::pedantic)]
#![cfg_attr(feature = "strict", deny(warnings))]

#[cfg(test)]
extern crate self as genawaiter;

pub use crate::ops::{Coroutine, Generator, GeneratorState};

#[cfg(feature = "proc_macro")]
use proc_macro_hack::proc_macro_hack;

/// Creates a producer for use with [`sync::Gen`].
///
/// A producer can later be turned into a generator using
/// [`Gen::new`](sync::Gen::new).
///
/// This macro takes one argument, which should be a block containing one or
/// more calls to [`yield_!`].
///
/// # Example
///
/// ```rust
/// use genawaiter::{sync::Gen, sync_producer as producer, yield_};
///
/// let my_producer = producer!({
///     yield_!(10);
/// });
///
/// let mut my_generator = Gen::new(my_producer);
/// # my_generator.resume();
/// ```
#[cfg(feature = "proc_macro")]
#[proc_macro_hack]
pub use genawaiter_proc_macro::sync_producer;

/// Creates a producer for use with [`rc::Gen`].
///
/// A producer can later be turned into a generator using
/// [`Gen::new`](rc::Gen::new).
///
/// This macro takes one argument, which should be a block containing one or
/// more calls to [`yield_!`].
///
/// # Example
///
/// ```rust
/// use genawaiter::{rc::Gen, rc_producer as producer, yield_};
///
/// let my_producer = producer!({
///     yield_!(10);
/// });
///
/// let mut my_generator = Gen::new(my_producer);
/// # my_generator.resume();
/// ```
#[cfg(feature = "proc_macro")]
#[proc_macro_hack]
pub use genawaiter_proc_macro::rc_producer;

#[doc(hidden)] // This is not quite usable currently, so hide it for now.
#[cfg(feature = "proc_macro")]
#[proc_macro_hack]
pub use genawaiter_proc_macro::stack_producer;

mod core;
mod ext;
#[macro_use]
mod macros;
mod ops;
pub mod rc;
pub mod stack;
pub mod sync;
#[cfg(test)]
mod testing;
mod waker;