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
//! This library provides a generator macro, to define generators. //! //! It is intended to explore one particular point in the design space of generators. More //! documentation can be found in the description of the attribute. #![feature(generator_trait)] /// This macro can be applied to functions to make them into generators. /// /// Functions annotated with this attribute use the `yield` keyword, instead of the `return` /// keyword. They yield an item and then continue. When you call a generator function, you get an /// iterator of the type it yields, rather than just one value of that type. /// /// You can still use the `return` keyword to terminate the generator early, but the `return` /// keyword cannot take a value; it only terminates the function. /// /// The behavior of `?` is also modified in these functions. In the event of an error, the /// generator yields the error value, and then the next time it is resumed it returns `None`. /// /// ## Forbidding self-references /// /// Unlike async functions, generators cannot contain self-references: a reference into their stack /// space that exists across a yield point. Instead, anything you wish to have by reference you /// should move out of the state of the generator, taking it as an argument, or else not holding it /// by reference across a point that you yield. /// /// ## Unstable features /// /// In order to use this attribute, you must turn on all of these features: /// - `generators` /// - `generator_trait` /// - `try_trait` /// /// ## Example /// /// ```rust /// #![feature(generators, generator_trait, try_trait)] /// /// #[propane::generator] /// fn fizz_buzz() -> String { /// for x in 1..101 { /// match (x % 3 == 0, x % 5 == 0) { /// (true, true) => yield String::from("FizzBuzz"), /// (true, false) => yield String::from("Fizz"), /// (false, true) => yield String::from("Buzz"), /// (..) => yield x.to_string(), /// } /// } /// } /// /// fn main() { /// let mut fizz_buzz = fizz_buzz(); /// assert_eq!(&fizz_buzz.next().unwrap()[..], "1"); /// assert_eq!(&fizz_buzz.next().unwrap()[..], "2"); /// assert_eq!(&fizz_buzz.next().unwrap()[..], "Fizz"); /// assert_eq!(&fizz_buzz.next().unwrap()[..], "4"); /// assert_eq!(&fizz_buzz.next().unwrap()[..], "Buzz"); /// assert_eq!(&fizz_buzz.next().unwrap()[..], "Fizz"); /// assert_eq!(&fizz_buzz.next().unwrap()[..], "7"); /// /// // yada yada yada /// let mut fizz_buzz = fizz_buzz.skip(90); /// /// assert_eq!(&fizz_buzz.next().unwrap()[..], "98"); /// assert_eq!(&fizz_buzz.next().unwrap()[..], "Fizz"); /// assert_eq!(&fizz_buzz.next().unwrap()[..], "Buzz"); /// assert!(fizz_buzz.next().is_none()); /// } /// ``` pub use propane_macros::generator; #[doc(hidden)] pub mod __internal { use std::marker::Unpin; use std::ops::{Generator, GeneratorState}; use std::pin::Pin; pub struct GenIter<G>(pub G); impl<G: Generator<Return = ()> + Unpin> Iterator for GenIter<G> { type Item = G::Yield; fn next(&mut self) -> Option<Self::Item> { match Pin::new(&mut self.0).resume(()) { GeneratorState::Yielded(item) => Some(item), GeneratorState::Complete(()) => None, } } } #[doc(hidden)] #[macro_export] macro_rules! gen_try { ($e:expr) => {{ use std::ops::Try; match Try::into_result($e) { Ok(ok) => ok, Err(err) => { yield <_ as Try>::from_error(err); return; } } }} } }