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
/// Pins a local to the stack.
///
/// This is used by [`mk_gen`]`!` to get a pollable generator without going
/// through a heap allocation (as [`Box::pin`] would do).
#[macro_export]
macro_rules! stack_pinned {
    (
        $var:ident
    ) => (
        let (ref $var,) = ($var,);
        let $var = unsafe {
            /// # Safety
            ///
            ///   - This is pin_utils' `pin_mut!` macro: the shadowing ensures
            ///     there is no longer access to the original stack variable,
            ///     which is thus impossible to move or forget.
            extern {}
            $crate::core::pin::Pin::new_unchecked($var)
        };
    );

    (
        mut $var:ident
    ) => (
        let (ref mut $var,) = ($var,);
        #[allow(unused_mut)]
        let mut $var = unsafe {
            /// # Safety
            ///
            ///   - This is pin_utils' `pin_mut!` macro: the shadowing ensures
            ///     there is no longer access to the original stack variable,
            ///     which is thus impossible to move or forget.
            extern {}
            $crate::core::pin::Pin::new_unchecked($var)
        };
    );
}

/// Instances a generator and pins it(required to be able to poll it).
///
/// By default it pins to the stack, but by using `box` it can pin to the heap
/// (necessary when wanting to return the generator itself).
///
/// # Usage
///
/// > `mk_gen!(let $(mut)? <varname> = $(box)? <generator fn> (<args>));`
///
/// # Example
///
/// ```rust
/// use ::next_gen::prelude::*;
///
/// #[generator(bool)]
/// fn toggler (initial: bool)
/// {
///     use ::core::ops::Not;
///
///     let mut current = initial;
///     loop {
///         yield_!(current);
///         current = current.not();
///     }
/// }
///
/// mk_gen!(let generator = toggler(true));
/// // a generator is not an iterator but an iterable:
/// let mut iterator = generator.into_iter();
///
/// assert_eq!(iterator.next(), Some(true));
/// assert_eq!(iterator.next(), Some(false));
/// assert_eq!(iterator.next(), Some(true));
/// assert_eq!(iterator.next(), Some(false));
/// assert_eq!(iterator.take(10_000).count(), 10_000);
/// ```
///
/// See [`GeneratorFn`] for more examples.
#[macro_export]
macro_rules! mk_gen {
    (@input
        let [$($mut:tt)?] $var:ident =
            box $generator:tt ( $($args:expr),* $(,)? )
        $(;)?
    ) => (
        let generator = $generator;
        let var = $crate::GeneratorFn::empty();
        let mut $var = ::std::boxed::Box::pin(var);
        $var .as_mut()
            .init(
                generator,
                ($($args, )*),
            )
        ;
    );

    (@input
        let [$($mut:tt)?] $var:ident =
            $generator:tt ( $($args:expr),* $(,)? )
        $(;)?
    ) => (
        let var = $crate::GeneratorFn::empty();
        $crate::stack_pinned!(mut var);
        var .as_mut()
            .init(
                $generator,
                ($($args, )*),
            )
        ;
        let $($mut)? $var = var;
    );

    (
        let mut $($tt:tt)*
    ) => (
        $crate::mk_gen!(@input let [mut] $($tt)*)
    );

    (
        let $($tt:tt)*
    ) => (
        $crate::mk_gen!(@input let [] $($tt)*)
    );
}

/// Emulate a `for`-loop iteration over a generator. The call itself evaluates
/// to the [`Return`][`crate::Generator::Return`] value of the [`Generator`][
/// `crate::Generator`].
///
/// # Example
///
/// ```rust
/// use ::next_gen::prelude::*;
///
/// type Question = &'static str;
/// type Answer = i32;
///
/// #[generator(Question)]
/// fn answer () -> Answer
/// {
///     yield_!("What is the answer to life, the universe and everything?");
///     42
/// }
///
/// let ret = gen_iter!(
///     for question in answer() {
///         assert_eq!(
///             question,
///             "What is the answer to life, the universe and everything?",
///         );
///     }
/// );
/// assert_eq!(ret, 42);
///
/// // You can also give it an already instanced generator:
///
/// mk_gen!(let mut generator = answer());
/// assert_eq!(
///     generator.as_mut().resume(),
///     ::next_gen::GeneratorState::Yield(
///         "What is the answer to life, the universe and everything?"
///     ),
/// );
///
/// let ret = gen_iter!(
///     for _ in generator {
///         unreachable!();
///     }
/// );
/// assert_eq!(ret, 42);
/// ```
/// ___
///
/// Note that you do not need this macro when you don't care about the return
/// value:
///
/// ```rust
/// use ::next_gen::prelude::*;
///
/// type Question = &'static str;
/// type Answer = i32;
///
/// #[generator(Question)]
/// fn answer () -> Answer
/// {
///     yield_!("What is the answer to life, the universe and everything?");
///     42
/// }
///
/// mk_gen!(let generator = answer());
///
/// for question in generator {
///     assert_eq!(
///         question,
///         "What is the answer to life, the universe and everything?",
///     );
/// }
/// ```
#[macro_export]
macro_rules! gen_iter {
    (
        for $pat:pat in $generator:tt ($($args:expr),* $(,)?) $block:block
    ) => ({
        $crate::mk_gen!(let generator = $generator ($($args),*));
        $crate::gen_iter!(
            for $pat in generator $block
        )
    });

    (
        for $pat:pat in $generator:tt $block:block
    ) => (match $generator { mut generator => {
        use $crate::{
            core::pin::Pin,
            Generator,
            GeneratorState,
        };
        let mut resume_generator = || -> GeneratorState<_, _> {
            Generator::resume(
                Pin::as_mut(&mut generator)
            )
        };
        loop {
            match resume_generator() {
                | GeneratorState::Yield($pat) => $block,
                | GeneratorState::Return(ret) => break ret,
            }
        }
    }});
}