Skip to main content

async_gen/
types.rs

1use std::{
2    pin::Pin,
3    task::{Context, Poll},
4};
5
6use futures_core::Stream;
7
8/// The result of a generator resumption.
9///
10/// This enum is returned from the `Generator::resume` method and indicates the
11/// possible return values of a generator. Currently this corresponds to either
12/// a suspension point (`Yielded`) or a termination point (`Complete`).
13#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
14pub enum GeneratorState<Y, R> {
15    /// The generator suspended with a value.
16    ///
17    /// This state indicates that a generator has been suspended, and typically
18    /// corresponds to a `yield` statement. The value provided in this variant
19    /// corresponds to the expression passed to `yield` and allows generators to
20    /// provide a value each time they yield.
21    Yielded(Y),
22
23    /// The generator completed with a return value.
24    ///
25    /// This state indicates that a generator has finished execution with the
26    /// provided value. Once a generator has returned `Complete` it is
27    /// considered a programmer error to call `resume` again.
28    Complete(R),
29}
30
31/// Generators, also commonly referred to as coroutines.
32pub trait AsyncGenerator {
33    /// The type of value this generator yields.
34    ///
35    /// This associated type corresponds to the `yield` expression and the
36    /// values which are allowed to be returned each time a generator yields.
37    /// For example an iterator-as-a-generator would likely have this type as
38    /// `T`, the type being iterated over.
39    type Yield;
40
41    /// The type of value this generator returns.
42    ///
43    /// This corresponds to the type returned from a generator either with a
44    /// `return` statement or implicitly as the last expression of a generator
45    /// literal. For example futures would use this as `Result<T, E>` as it
46    /// represents a completed future.
47    type Return;
48
49    /// Resumes the execution of this generator.
50    ///
51    /// This function will resume execution of the generator or start execution
52    /// if it hasn't already. This call will return back into the generator's
53    /// last suspension point, resuming execution from the latest `yield`. The
54    /// generator will continue executing until it either yields or returns, at
55    /// which point this function will return.
56    ///
57    /// # Return value
58    ///
59    /// The `GeneratorState` enum returned from this function indicates what
60    /// state the generator is in upon returning. If the `Yielded` variant is
61    /// returned then the generator has reached a suspension point and a value
62    /// has been yielded out. Generators in this state are available for
63    /// resumption at a later point.
64    ///
65    /// If `Complete` is returned then the generator has completely finished
66    /// with the value provided. It is invalid for the generator to be resumed
67    /// again.
68    ///
69    /// # Panics
70    ///
71    /// This function may panic if it is called after the `Complete` variant has
72    /// been returned previously. While generator literals in the language are
73    /// guaranteed to panic on resuming after `Complete`, this is not guaranteed
74    /// for all implementations of the `Generator` trait.
75    fn poll_resume(
76        self: Pin<&mut Self>,
77        cx: &mut Context<'_>,
78    ) -> Poll<GeneratorState<Self::Yield, Self::Return>>;
79}
80
81impl<S: Stream> AsyncGenerator for S {
82    type Yield = S::Item;
83    type Return = ();
84
85    #[inline]
86    fn poll_resume(
87        self: Pin<&mut Self>,
88        cx: &mut Context<'_>,
89    ) -> Poll<GeneratorState<Self::Yield, Self::Return>> {
90        self.poll_next(cx).map(|val| match val {
91            Some(val) => GeneratorState::Yielded(val),
92            None => GeneratorState::Complete(()),
93        })
94    }
95}