next-gen 0.0.6

Safe generators on stable Rust.
Documentation
use super::{*,
    generator::__Internals_YieldSlot_DoNotUse__ as YieldSlot,
};
use ::core::iter::FromIterator;

macro_rules! assert_it_eq {(
    $left:expr, $right:expr $(, $($msg:expr $(,)?)?)?
) => (
    assert_eq!(
        $left.into_iter().collect::<Vec<_>>(),
        $right,
        $($($msg ,)?)?
    )
)}

macro_rules! make_yield {
    (
        @with_dollar![$dol:tt]
        $co:expr
    ) => (
        macro_rules! yield_ {(
            $dol value:expr
        ) => (
            $co.put($dol value).await
        )}
    );

    (
        $co:expr
    ) => (
        make_yield!(
            @with_dollar![$]
            $co
        )
    )
}

#[test]
fn basic ()
{
    async fn generator<'foo> (out: YieldSlot<'foo, u8>, _: ()) {
        make_yield!(out);

        yield_!(42);
        yield_!(0);
        yield_!(27);
    }

    mk_gen!(let generator = generator());
    assert_it_eq!(
        generator,
        [42, 0, 27],
    );
}

#[test]
fn range ()
{
    async fn range (out: YieldSlot<'_, u8>, (start, end): (u8, u8)) {
        make_yield!(out);

        let mut current = start;
        while current < end {
            yield_!(current);
            current += 1;
        }
    }

    mk_gen!(let generator = range(2, 8));
    assert_it_eq!(
        generator,
        Vec::from_iter(2 .. 8),
    );
}

mod proc_macros {
    use super::*;
    mod next_gen {
        pub(in super) use crate::*;
    }
    use ::proc_macro::generator;

    #[test]
    fn range ()
    {
        #[generator(u8)]
        fn range (start: u8, end: u8)
        {
            let mut current = start;
            while current < end {
                yield_!(current);
                current += 1;
            }
        }

        mk_gen!(let generator = range(2, 8));
        assert_it_eq!(
            generator,
            Vec::from_iter(2 .. 8),
        );
    }

    #[test]
    fn gen_iter ()
    {
        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);
    }

    mod adaptors {
        use super::*;

        #[generator(T)]
        fn filter<T> (
            mut predicate: impl FnMut(&T) -> bool,
            iterable: impl IntoIterator<Item = T>,
        )
        {
            for element in iterable {
                if predicate(&element) {
                    yield_!(element);
                }
            }
        }

        #[generator(U)]
        fn map<T, U> (
            mut f: impl FnMut(T) -> U,
            iterable: impl IntoIterator<Item = T>,
        )
        {
            for element in iterable {
                yield_!(f(element));
            }
        }

        #[generator(u8)]
        fn range (start: u8, end: u8)
        {
            let mut current = start;
            while current < end {
                yield_!(current);
                current += 1;
            }
        }

        #[test]
        fn filter_range ()
        {

            mk_gen!(let iterator = range(2, 7));
            mk_gen!(let iterator = filter(|x| x % 2 == 0, iterator));
            assert_it_eq!(
                iterator,
                [2, 4, 6],
            );
        }

        #[test]
        fn filter_map_range ()
        {

            mk_gen!(let iterator = range(2, 7));
            mk_gen!(let iterator = filter(|x| x % 2 == 0, iterator));
            mk_gen!(let iterator = map(|x| x * x, iterator));
            assert_it_eq!(
                iterator,
                [4, 16, 36],
            );
        }
    }
}