fauxgen/lib.rs
1//! This crate implements generators for Rust.
2//!
3//! Rust has built-in generators but they are currently unstable and so they can
4//! only be used on nightly. This crate allows you to write your own generators
5//! on stable rust by using async-await underneath the hood.
6//!
7//! # Defining a Generator
8//! This crate provides two different ways to define generators. The first is as
9//! a top-level function:
10//!
11//! ```
12//! #[fauxgen::generator(yield = i32)]
13//! fn generator() {
14//! r#yield!(1);
15//! r#yield!(2);
16//! }
17//! ```
18//!
19//! and the second is as a lambda using the [`gen!`] macro:
20//!
21//! ```
22//! use fauxgen::{gen, GeneratorToken};
23//!
24//! let generator = fauxgen::gen!(|token: GeneratorToken<_>| {
25//! token.yield_(1i32).await;
26//! token.yield_(2i32).await;
27//! });
28//! ```
29//!
30//! In this case the generator uses a [`GeneratorToken`] instead of the `yield!`
31//! macro.
32//!
33//! Generators can also be async
34//! ```
35//! use std::time::Duration;
36//!
37//! #[fauxgen::generator(yield = u32)]
38//! async fn generator() {
39//! for i in 0u32..10 {
40//! tokio::time::sleep(Duration::from_millis(50)).await;
41//! r#yield!(i * 2);
42//! }
43//! }
44//! ```
45//!
46//! # Using a Generator
47//! Generators all implement either [`Generator`] or [`AsyncGenerator`]. Simple
48//! generators implement either [`Iterator`] or
49//! [`Stream`](futures_core::Stream), depending on whether the generator is
50//! async. This means that you can easily combine generators.
51//!
52//! Here we implement a generator that returns all the powers of two for a u32:
53//! ```
54//! #[fauxgen::generator(yield = u32)]
55//! fn range(max: u32) {
56//! for i in 0..max {
57//! r#yield!(i);
58//! }
59//! }
60//!
61//! #[fauxgen::generator(yield = u32)]
62//! fn powers_of_two() {
63//! for i in std::pin::pin!(range(31)) {
64//! r#yield!(1 << i);
65//! }
66//! }
67//! ```
68//!
69//! Note that because `fauxgen` generators are actually rust futures under the
70//! hood you will need to pin them before you can use them.
71//!
72//! # More Advanced Generator Usage
73//! Most use cases for generators will likely involve using them as iterators or
74//! streams. However, that is not all that they can do. In addition to the yield
75//! parameter, generators have both
76//! - an argument: which is the value passed in to `resume`, and,
77//! - a return value: which is the value returned when the generator completes.
78//!
79//! A complete generator that uses all of these looks like this:
80//! ```
81//! use fauxgen::{GeneratorState, Generator};
82//!
83//! #[fauxgen::generator(yield = String, arg = u32)]
84//! fn format_each() -> u64 {
85//! let mut count = 0;
86//! let mut value = 0;
87//!
88//! while value < 100 {
89//! value = r#yield!(value.to_string());
90//! count += 1;
91//! }
92//!
93//! count
94//! }
95//!
96//! let mut gen = std::pin::pin!(format_each());
97//!
98//! for value in [0, 5, 10, 25, 125, 87, 31] {
99//! match gen.as_mut().resume(value) {
100//! GeneratorState::Yielded(text) => println!("{text}"),
101//! GeneratorState::Complete(count) => {
102//! println!("printed {count} items");
103//! break;
104//! }
105//! }
106//! }
107//! ```
108//!
109//! This is obviously somewhat harder to use than just using the generator as an
110//! iterator but it does give you more abilities to use.
111//!
112//! ## Accessing the first argument
113//! If you run the code above (or look closely) then you might notice that the
114//! first argument passed into the generator is ignored. This usually isn't
115//! what you want. In order to access the first argument you can use the
116//! `argument!` macro:
117//!
118//! ```
119//! #[fauxgen::generator(yield = String, arg = u32)]
120//! fn format_each() -> u32 {
121//! let mut count = 0;
122//! let mut value = argument!();
123//!
124//! while value < 100 {
125//! value = r#yield!(value.to_string());
126//! count += 1;
127//! }
128//!
129//! count
130//! }
131//! ```
132//!
133//! Note that using the `argument!` macro after you have called `yield!` is
134//! likely to result in a panic.
135
136#![cfg_attr(std_generators, feature(generator_trait))]
137
138extern crate self as fauxgen;
139
140// A small helper macro to avoid unused_imports warnings for items that have
141// only been pulled in to scope so they can be referred to in docs.
142macro_rules! used_in_docs {
143 ($( $name:ident ),+ $(,)? ) => {
144 const _: () = {
145 #[allow(unused_imports)]
146 mod _used_in_docs {
147 $( use super::$name; )+
148 }
149 };
150 };
151}
152
153#[path = "async.rs"]
154mod asynk;
155mod detail;
156mod export;
157mod impls;
158mod iter;
159mod stream;
160mod token;
161
162#[cfg(not(std_generators))]
163mod core;
164
165#[cfg(std_generators)]
166mod core {
167 pub use std::ops::{Generator, GeneratorState};
168}
169
170#[doc = include_str!("../README.md")]
171mod readme {}
172
173/// Declare a standalone generator function.
174///
175/// This attribute macro transforms a function definition into a generator
176/// definition.
177///
178/// # Parameters
179/// - `yield` - The type that will be yielded from the generator. If not
180/// specified then `()` will be used instead.
181/// - `arg` - The type of the argument that will be passed to the generator via
182/// `resume`. This can be accessed via the `argument!` and `r#yield!` macros
183/// within the generator.
184/// - `crate` - A path at which the fauxgen crate can be accessed. If not
185/// specified then it will use `::fauxgen`.
186///
187/// # Interface
188/// This attribute macro creates two regular macros that can only be used inside
189/// the generator definition itself:
190/// ## `r#yield!`
191/// This is the equivalent of the yield keyword. It takes a value to yield to
192/// the caller and returns the argument that was passed in on resume.
193///
194/// ```
195/// use fauxgen::{Generator, GeneratorState};
196///
197/// #[fauxgen::generator(yield = &'static str, arg = &'static str)]
198/// fn example() -> &'static str {
199/// r#yield!("test")
200/// }
201///
202/// let mut gen = std::pin::pin!(example());
203/// assert!(matches!(gen.as_mut().resume("ignored"), GeneratorState::Yielded("test")));
204/// assert!(matches!(gen.as_mut().resume("another"), GeneratorState::Complete("another")));
205/// ```
206///
207/// Note, however, that the first argument passed into the generator is ignored.
208/// In order to extract the first argument we need to use the `argument!` macro.
209///
210/// ## `argument!`
211/// This macro extracts the argument passed to the very first resume call, the
212/// one that started the generator. It is only valid to call before the first
213/// yield, doing so after will result in a panic.
214///
215/// ```
216/// #[fauxgen::generator(arg = &'static str)]
217/// fn example() {
218/// let first = argument!();
219/// let second = r#yield!();
220/// let third = r#yield!();
221/// }
222/// ```
223///
224/// # Using the `yield` keyword
225/// This macro supports using the `yield` keyword in place of the `r#yield!`
226/// macro. Note that the keyword itself is unstable in rust and to just use it
227/// you will need to enable the nightly `generators` feature.
228#[cfg_attr(nightly, doc = "```")]
229#[cfg_attr(not(nightly), doc = "```ignore")]
230/// #![feature(coroutines)]
231///
232/// #[fauxgen::generator(yield = &'static str)]
233/// fn generator() {
234/// yield "first";
235/// yield "second";
236/// yield "third";
237/// }
238/// ```
239#[cfg(feature = "macros")]
240pub use fauxgen_macros::generator;
241
242pub use crate::asynk::{AsyncGenerator, Resume};
243pub use crate::core::{Generator, GeneratorState};
244pub use crate::iter::GeneratorIter;
245pub use crate::stream::{GeneratorStream, GeneratorTryStream};
246pub use crate::token::GeneratorToken;
247
248/// Declare an inline generator function.
249///
250/// This is a declarative version of the [`generator`] macro. It can be used to
251/// declare a generator inline without giving it a named function.
252///
253/// Unlike with the [`generator`] macro, this generator type instead takes in a
254/// [`GeneratorToken`] which is used to yield values and to access generator
255/// arguments.
256///
257/// # Example
258/// The simplest type of generator is one which only yields values:
259/// ```
260/// use fauxgen::{gen, GeneratorToken};
261///
262/// let gen = gen!(|token: GeneratorToken<_>| {
263/// token.yield_(5i32).await;
264/// token.yield_(6).await;
265/// token.yield_(77).await;
266/// });
267/// let gen = std::pin::pin!(gen);
268///
269/// let vals: Vec<i32> = gen.collect();
270/// assert_eq!(vals, [5, 6, 77]);
271/// ```
272///
273/// # Interface
274/// The interface exposed here is similar, in principle, to that offered by the
275/// [`generator`] macro. You can await upon the methods exposed by the
276/// [`GeneratorToken`] in order to both yield a value as well as to get the
277/// first generator argument.
278///
279/// See the documentation of the [`generator`] macro for a description of what
280/// each one does.
281///
282/// # Restrictions
283/// This macro allows you to use await within the generator. However, it is an
284/// error to do this unless the generator is async. Awaiting on a future other
285/// than those gotten by calling methods on the [`GeneratorToken`] will result
286/// in a panic for sync generators.
287#[cfg(doc)]
288#[macro_export]
289macro_rules! gen {
290 (async $(move)? $func:expr) => {};
291 ( $(move)? $func:expr) => {};
292}
293
294/// Declare an inline generator function.
295#[cfg(not(doc))]
296#[macro_export]
297macro_rules! gen {
298 (async $(move $($dummy:tt)?)? |$token:ident$( : $ty:ty)?| $body:expr) => {{
299 let func = $(move $($dummy)?)? |$token $( : $ty)?| async move { $body };
300 $crate::gen_impl!(gen_async => func)
301 }};
302 ($(move $($dummy:tt)?)? |$token:ident$( : $ty:ty)?| $body:expr) => {{
303 let func = $(move $($dummy)?)? |$token $( : $ty)?| async move { $body };
304 $crate::gen_impl!(gen_sync => func)
305 }};
306}
307
308#[macro_export]
309#[doc(hidden)]
310macro_rules! gen_impl {
311 ($genfn:ident => $func:expr) => {{
312 let token = $crate::__private::token();
313
314 $crate::__private::$genfn(token.marker(), async move {
315 let token: $crate::GeneratorToken<_, _> =
316 $crate::__private::register_owned(token).await;
317 $func(token).await
318 })
319 }};
320}
321
322#[doc(hidden)]
323pub mod __private {
324 use std::pin::Pin;
325
326 use crate::GeneratorToken;
327
328 // separate exports ..
329 #[allow(dead_code)]
330 fn _dummy() {}
331
332 pub use std::future::Future;
333 pub use std::pin::pin;
334
335 pub use crate::detail::{RawGeneratorToken, TokenMarker};
336 pub use crate::export::{AsyncGenerator, SyncGenerator};
337
338 pub fn gen_sync<F, Y, A>(_: TokenMarker<Y, A>, future: F) -> SyncGenerator<F, Y, A> {
339 SyncGenerator::new(future)
340 }
341
342 pub fn gen_async<F, Y, A>(_: TokenMarker<Y, A>, future: F) -> AsyncGenerator<F, Y, A> {
343 AsyncGenerator::new(future)
344 }
345
346 pub fn token<Y, A>() -> RawGeneratorToken<Y, A> {
347 RawGeneratorToken::new()
348 }
349
350 pub async fn register<Y, A>(token: Pin<&RawGeneratorToken<Y, A>>) {
351 // SAFETY: register is only called from the prelude generated by the
352 // #[generator] macro. The macro takes responsibility for ensuring that
353 // the parameters match.
354 unsafe { token.register().await }
355 }
356
357 pub async fn register_owned<Y, A>(token: RawGeneratorToken<Y, A>) -> GeneratorToken<Y, A> {
358 // SAFETY: register_owned is only called from the code emitted by the gen!
359 // macro. The macro takes responsibility for ensuring that the
360 // parameters match.
361 unsafe { GeneratorToken::register(token).await }
362 }
363}