genawaiter-0.99.1/Cargo.toml.orig000064400000000000000000000022151363130477400150250ustar0000000000000000# https://doc.rust-lang.org/cargo/reference/manifest.html [package] name = "genawaiter" version = "0.99.1" authors = ["John Simon "] edition = "2018" license = "MIT" description = "Stackless generators on stable Rust." repository = "https://github.com/whatisaphone/genawaiter" documentation = "https://docs.rs/genawaiter" readme = "README-crates-io.md" keywords = ["generator", "yield", "coroutine", "async", "await"] categories = ["asynchronous", "concurrency", "rust-patterns"] include = ["Cargo.toml", "README-crates-io.md", "src/**/*.rs"] [dependencies] futures-core = { version = "0.3.1", optional = true } genawaiter-proc-macro = { version = "0.99.1", path = "./genawaiter-proc-macro", optional = true } genawaiter-macro = { version = "0.99.1", path = "./genawaiter-macro" } proc-macro-hack = { version = "0.5", optional = true } [workspace] members = ["genawaiter-macro", "genawaiter-proc-macro"] [dev-dependencies] futures = "0.3.1" once_cell = "1.3.1" [features] default = ["proc_macro"] futures03 = ["futures-core"] nightly = [] strict = [] proc_macro = ["genawaiter-proc-macro", "proc-macro-hack", "genawaiter-macro/proc_macro"] genawaiter-0.99.1/Cargo.toml0000644000000030221363130534200113530ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] edition = "2018" name = "genawaiter" version = "0.99.1" authors = ["John Simon "] include = ["Cargo.toml", "README-crates-io.md", "src/**/*.rs"] description = "Stackless generators on stable Rust." documentation = "https://docs.rs/genawaiter" readme = "README-crates-io.md" keywords = ["generator", "yield", "coroutine", "async", "await"] categories = ["asynchronous", "concurrency", "rust-patterns"] license = "MIT" repository = "https://github.com/whatisaphone/genawaiter" [dependencies.futures-core] version = "0.3.1" optional = true [dependencies.genawaiter-macro] version = "0.99.1" [dependencies.genawaiter-proc-macro] version = "0.99.1" optional = true [dependencies.proc-macro-hack] version = "0.5" optional = true [dev-dependencies.futures] version = "0.3.1" [dev-dependencies.once_cell] version = "1.3.1" [features] default = ["proc_macro"] futures03 = ["futures-core"] nightly = [] proc_macro = ["genawaiter-proc-macro", "proc-macro-hack", "genawaiter-macro/proc_macro"] strict = [] genawaiter-0.99.1/README-crates-io.md000064400000000000000000000034111363130477400153000ustar0000000000000000# genawaiter [![crate-badge]][crate-link] [![docs-badge]][docs-link] [![ci-badge]][ci-link] [crate-badge]: https://img.shields.io/crates/v/genawaiter.svg [crate-link]: https://crates.io/crates/genawaiter [docs-badge]: https://docs.rs/genawaiter/badge.svg [docs-link]: https://docs.rs/genawaiter [ci-badge]: https://github.com/whatisaphone/genawaiter/workflows/CI/badge.svg [ci-link]: https://github.com/whatisaphone/genawaiter/actions This crate implements stackless generators (aka coroutines) in stable Rust. Instead of using `yield`, which [won't be stabilized anytime soon][yield-unstable], you use `async`/`await`, which is stable today. [yield-unstable]: https://doc.rust-lang.org/nightly/unstable-book/language-features/generators.html Features: - supports resume arguments and completion values - supports async generators (e.g., `Stream`s) - allocation-free - no runtime dependencies - no compile-time dependencies either, with `default-features = false` - built on top of standard language constructs, which means there are no platform-specific shenanigans Example: ```rust let odd_numbers_less_than_ten = gen!({ let mut n = 1; while n < 10 { yield_!(n); // Suspend a function at any point with a value. n += 2; } }); // Generators can be used as ordinary iterators. for num in odd_numbers_less_than_ten { println!("{}", num); } ``` Result: ```text 1 3 5 7 9 ``` And here is the same generator, this time without macros. This is how you do things with `default-features = false` (which eliminates the proc macro dependencies). ```rust let odd_numbers_less_than_ten = Gen::new(|co| async move { let mut n = 1; while n < 10 { co.yield_(n).await; n += 2; } }); ``` [See the docs for more.](https://docs.rs/genawaiter) genawaiter-0.99.1/src/core.rs000064400000000000000000000121621363127274000142220ustar0000000000000000use crate::{ops::GeneratorState, waker}; use std::{ future::Future, pin::Pin, task::{Context, Poll}, }; pub enum Next { Empty, Yield(Y), Resume(R), Completed, } #[allow(clippy::use_self)] impl Next { pub fn without_values(&self) -> Next<(), ()> { match self { Self::Empty => Next::Empty, Self::Yield(_) => Next::Yield(()), Self::Resume(_) => Next::Resume(()), Self::Completed => Next::Completed, } } } pub fn advance( future: Pin<&mut F>, airlock: &impl Airlock, ) -> GeneratorState { let waker = waker::create(); let mut cx = Context::from_waker(&waker); match future.poll(&mut cx) { Poll::Pending => { let value = airlock.replace(Next::Empty); match value { Next::Empty | Next::Completed => unreachable!(), Next::Yield(y) => GeneratorState::Yielded(y), Next::Resume(_) => { #[cfg(debug_assertions)] panic!( "An async generator was resumed via a non-async method. For \ async generators, use `Stream` or `async_resume` instead of \ `Iterator` or `resume`.", ); #[cfg(not(debug_assertions))] panic!("misused async generator"); } } } Poll::Ready(value) => { #[cfg(debug_assertions)] airlock.replace(Next::Completed); GeneratorState::Complete(value) } } } pub fn async_advance<'a, Y, R, F: Future>( future: Pin<&'a mut F>, airlock: impl Airlock + 'a, ) -> impl Future> + 'a { Advance { future, airlock } } struct Advance<'a, F: Future, A: Airlock> { future: Pin<&'a mut F>, airlock: A, } impl<'a, F: Future, A: Airlock> Advance<'a, F, A> { fn future_mut(self: Pin<&mut Self>) -> Pin<&mut F> { // Safety: This is just projecting a pinned reference. Neither `self` nor // `self.future` are moved. unsafe { self.map_unchecked_mut(|s| s.future.as_mut().get_unchecked_mut()) } } } impl<'a, F: Future, A: Airlock> Future for Advance<'a, F, A> { type Output = GeneratorState; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { match self.as_mut().future_mut().poll(cx) { Poll::Pending => { let value = self.airlock.replace(Next::Empty); match value { Next::Empty | Next::Resume(_) => Poll::Pending, Next::Yield(y) => Poll::Ready(GeneratorState::Yielded(y)), Next::Completed => unreachable!(), } } Poll::Ready(value) => { #[cfg(debug_assertions)] self.airlock.replace(Next::Completed); Poll::Ready(GeneratorState::Complete(value)) } } } } pub trait Airlock { type Yield; type Resume; fn peek(&self) -> Next<(), ()>; fn replace( &self, next: Next, ) -> Next; } pub struct Co { airlock: A, } impl Co { pub(crate) fn new(airlock: A) -> Self { Self { airlock } } /// Yields a value from the generator. /// /// The caller should immediately `await` the result of this function. /// /// [_See the module-level docs for examples._](.) pub fn yield_(&self, value: A::Yield) -> impl Future + '_ { #[cfg(debug_assertions)] match self.airlock.peek() { Next::Yield(()) => { panic!( "Multiple values were yielded without an intervening await. Make \ sure to immediately await the result of `Co::yield_`." ); } Next::Completed => { panic!( "`yield_` should not be used after the generator completes. The \ `Co` object should have been dropped by now." ) } Next::Empty | Next::Resume(()) => {} } self.airlock.replace(Next::Yield(value)); Barrier { airlock: &self.airlock, } } } struct Barrier<'a, A: Airlock> { airlock: &'a A, } impl<'a, A: Airlock> Future for Barrier<'a, A> { type Output = A::Resume; fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { match self.airlock.peek() { Next::Yield(_) => Poll::Pending, Next::Resume(_) => { let next = self.airlock.replace(Next::Empty); match next { Next::Resume(arg) => Poll::Ready(arg), Next::Empty | Next::Yield(_) | Next::Completed => unreachable!(), } } Next::Empty | Next::Completed => unreachable!(), } } } genawaiter-0.99.1/src/ext.rs000064400000000000000000000005541356112467200140760ustar0000000000000000#![allow(clippy::module_name_repetitions)] use std::mem; pub trait MaybeUninitExt { unsafe fn assume_init_get_mut(&mut self) -> &mut T; } impl MaybeUninitExt for mem::MaybeUninit { // Copy of unstable method `MaybeUninit::get_mut`. unsafe fn assume_init_get_mut(&mut self) -> &mut T { self.as_mut_ptr().as_mut().unwrap() } } genawaiter-0.99.1/src/lib.rs000064400000000000000000000224211362231764400140420ustar0000000000000000/*! This crate implements generators for Rust. Generators are a feature common across many programming language. They let you yield a sequence of values from a function. A few common use cases are: - Easily building iterators. - Avoiding allocating a list for a function which returns multiple values. Rust has this feature too, but it is currently unstable (and thus nightly-only). But with this crate, you can use them on stable Rust! # Features This crate has these features: - `futures03` (disabled by default) – Implements `Stream` for all generator types. Adds a dependency on `futures-core`. - `proc_macro` (enabled by default) – Adds support for macros, and adds various compile-time dependencies. # Choose your guarantees This crate supplies three concrete implementations of generators: 1. [`genawaiter::stack`](stack) – Allocation-free. You should prefer this when possible. 2. [`genawaiter::rc`](rc) – This allocates. 3. [`genawaiter::sync`](sync) – This allocates, and can be shared between threads. [unus]: https://github.com/whatisaphone/genawaiter/blob/4a2b185/src/waker.rs#L9 [duo]: https://github.com/whatisaphone/genawaiter/blob/4a2b185/src/rc/engine.rs#L26 Here are the differences in table form: | | [`stack::Gen`] | [`rc::Gen`] | [`sync::Gen`] | |---------------------------------------|----------------|-------------|---------------| | Allocations per generator | 0 | 2 | 2 | | Generator can be moved after created | no | yes | yes | | Thread-safe | no | no | yes | # Creating a generator Once you've chosen how and whether to allocate (see previous section), you can create a generator using a macro from the `gen` family: - [`stack::let_gen!`](stack/macro.let_gen.html) - [`rc::gen!`](rc/macro.gen.html) - [`sync::gen!`](sync/macro.gen.html) ```rust # #[cfg(feature = "proc_macro")] # fn feature_gate() { # use genawaiter::{sync::gen, yield_}; # let count_to_ten = gen!({ for n in 0..10 { yield_!(n); } }); # let result: Vec<_> = count_to_ten.into_iter().collect(); # assert_eq!(result, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); # } ``` To re-use logic between multiple generators, you can use a macro from the `producer` family, and then pass the producer to `Gen::new`. - [`stack_producer!`] and [`let_gen_using!`](stack/macro.let_gen_using.html) - [`rc_producer!`] and [`Gen::new`](rc::Gen::new) - [`sync_producer!`] and [`Gen::new`](sync::Gen::new) ```rust # #[cfg(feature = "proc_macro")] # fn feature_gate() { # use genawaiter::{sync::Gen, sync_producer as producer, yield_}; # let count_producer = producer!({ for n in 0..10 { yield_!(n); } }); let count_to_ten = Gen::new(count_producer); # let result: Vec<_> = count_to_ten.into_iter().collect(); # assert_eq!(result, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); # } ``` If neither of these offers enough control for you, you can always skip the macros and use the low-level API directly: ```rust # use genawaiter::sync::{Co, Gen}; # let count_to_ten = Gen::new(|co| async move { for n in 0..10 { co.yield_(n).await; } }); # let result: Vec<_> = count_to_ten.into_iter().collect(); # assert_eq!(result, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); ``` # A tale of three types A generator can control the flow of up to three types of data: - **Yield** – Each time a generator suspends execution, it can produce a value. - **Resume** – Each time a generator is resumed, a value can be passed in. - **Completion** – When a generator completes, it can produce one final value. ## Yield Values can be yielded from the generator by calling `yield_`, and immediately awaiting the future it returns. You can get these values out of the generator in either of two ways: - Call `resume()` or `resume_with()`. The values will be returned in a `GeneratorState::Yielded`. ```rust # #[cfg(feature = "proc_macro")] # fn feature_gate() { # use genawaiter::{sync::gen, yield_, GeneratorState}; # let mut generator = gen!({ yield_!(10); }); let ten = generator.resume(); assert_eq!(ten, GeneratorState::Yielded(10)); # } ``` - Treat it as an iterator. For this to work, both the resume and completion types must be `()` . ```rust # #[cfg(feature = "proc_macro")] # fn feature_gate() { # use genawaiter::{sync::gen, yield_}; # let generator = gen!({ yield_!(10); }); let xs: Vec<_> = generator.into_iter().collect(); assert_eq!(xs, [10]); # } ``` ## Resume You can also send values back into the generator, by using `resume_with`. The generator receives them from the future returned by `yield_`. ```rust # #[cfg(feature = "proc_macro")] # fn feature_gate() { # use genawaiter::{sync::gen, yield_}; # let mut printer = gen!({ loop { let string = yield_!(()); println!("{}", string); } }); printer.resume_with("hello"); printer.resume_with("world"); # } ``` ## Completion A generator can produce one final value upon completion, by returning it from the function. The consumer will receive this value as a `GeneratorState::Complete`. ```rust # #[cfg(feature = "proc_macro")] # fn feature_gate() { # use genawaiter::{sync::gen, yield_, GeneratorState}; # let mut generator = gen!({ yield_!(10); "done" }); assert_eq!(generator.resume(), GeneratorState::Yielded(10)); assert_eq!(generator.resume(), GeneratorState::Complete("done")); # } ``` # Async generators If you await other futures inside the generator, it becomes an _async generator_. It does not makes sense to treat an async generator as an `Iterable`, since you cannot `await` an `Iterable`. Instead, you can treat it as a `Stream`. This requires opting in to the dependency on `futures` with the `futures03` feature. ```toml [dependencies] genawaiter = { version = "...", features = ["futures03"] } ``` ```rust # #[cfg(all(feature = "proc_macro", feature = "futures03"))] # fn feature_gate() { # use futures::executor::block_on_stream; # use genawaiter::{sync::gen, yield_}; # async fn async_one() -> i32 { 1 } async fn async_two() -> i32 { 2 } let gen = gen!({ let one = async_one().await; yield_!(one); let two = async_two().await; yield_!(two); }); let stream = block_on_stream(gen); let items: Vec<_> = stream.collect(); assert_eq!(items, [1, 2]); # } ``` Async generators also provide a `async_resume` method for lower-level control. (This works even without the `futures03` feature.) ```rust # #[cfg(feature = "proc_macro")] # async fn feature_gate() { # use genawaiter::{sync::gen, yield_, GeneratorState}; # use std::task::Poll; # # let mut gen = gen!({ # yield_!(10); # }); # match gen.async_resume().await { GeneratorState::Yielded(_) => {} GeneratorState::Complete(_) => {} } # } ``` # Backported stdlib types This crate supplies [`Generator`](trait.Generator.html) and [`GeneratorState`](enum.GeneratorState.html). They are copy/pasted from the stdlib (with stability attributes removed) so they can be used on stable Rust. If/when real generators are stabilized, hopefully they would be drop-in replacements. Javascript developers might recognize this as a polyfill. There is also a [`Coroutine`](trait.Coroutine.html) trait, which does not come from the stdlib. A `Coroutine` is a generalization of a `Generator`. A `Generator` constrains the resume argument type to `()`, but in a `Coroutine` it can be anything. */ #![cfg_attr(feature = "nightly", feature(async_closure))] #![warn(future_incompatible, rust_2018_compatibility, rust_2018_idioms, unused)] #![warn(missing_docs, clippy::cargo, clippy::pedantic)] #![cfg_attr(feature = "strict", deny(warnings))] #[cfg(test)] extern crate self as genawaiter; pub use crate::ops::{Coroutine, Generator, GeneratorState}; #[cfg(feature = "proc_macro")] use proc_macro_hack::proc_macro_hack; /// Creates a producer for use with [`sync::Gen`]. /// /// A producer can later be turned into a generator using /// [`Gen::new`](sync::Gen::new). /// /// This macro takes one argument, which should be a block containing one or /// more calls to [`yield_!`]. /// /// # Example /// /// ```rust /// use genawaiter::{sync::Gen, sync_producer as producer, yield_}; /// /// let my_producer = producer!({ /// yield_!(10); /// }); /// /// let mut my_generator = Gen::new(my_producer); /// # my_generator.resume(); /// ``` #[cfg(feature = "proc_macro")] #[proc_macro_hack] pub use genawaiter_proc_macro::sync_producer; /// Creates a producer for use with [`rc::Gen`]. /// /// A producer can later be turned into a generator using /// [`Gen::new`](rc::Gen::new). /// /// This macro takes one argument, which should be a block containing one or /// more calls to [`yield_!`]. /// /// # Example /// /// ```rust /// use genawaiter::{rc::Gen, rc_producer as producer, yield_}; /// /// let my_producer = producer!({ /// yield_!(10); /// }); /// /// let mut my_generator = Gen::new(my_producer); /// # my_generator.resume(); /// ``` #[cfg(feature = "proc_macro")] #[proc_macro_hack] pub use genawaiter_proc_macro::rc_producer; #[doc(hidden)] // This is not quite usable currently, so hide it for now. #[cfg(feature = "proc_macro")] #[proc_macro_hack] pub use genawaiter_proc_macro::stack_producer; mod core; mod ext; #[macro_use] mod macros; mod ops; pub mod rc; pub mod stack; pub mod sync; #[cfg(test)] mod testing; mod waker; genawaiter-0.99.1/src/macros.rs000064400000000000000000000017771362212171100145570ustar0000000000000000/// Yields a value from a generator. /// /// This macro can only be used inside the `gen!` and `producer!` families of /// macros. /// /// It will suspend execution of the function until the generator is resumed. At /// that time, it will evaluate to the resume argument, if given, otherwise it /// will evaluate to `()`. /// /// # Examples /// /// [_See the module-level docs for examples._](.) #[cfg(feature = "proc_macro")] #[macro_export] macro_rules! yield_ { ($val:expr) => { compile_error!( "`yield_!()` can only be used inside one of the genawaiter macros", ) }; (@__impl => $co:expr, $value:expr) => { $co.yield_($value).await }; } // Internal use only. This is a copy of `futures::pin_mut!` so we can avoid // pulling in a dependency for a two-liner. #[cfg(feature = "futures03")] macro_rules! pin_mut { ($x:ident) => { let mut $x = $x; #[allow(unused_mut)] let mut $x = unsafe { ::std::pin::Pin::new_unchecked(&mut $x) }; }; } genawaiter-0.99.1/src/ops.rs000064400000000000000000000034501362127560400140740ustar0000000000000000use std::pin::Pin; /// A trait implemented for coroutines. /// /// A `Coroutine` is a generalization of a `Generator`. A `Generator` constrains /// the resume argument type to `()`, but in a `Coroutine` it can be anything. pub trait Coroutine { /// The type of value this generator yields. type Yield; /// The type of value this generator accepts as a resume argument. type Resume; /// The type of value this generator returns upon completion. type Return; /// Resumes the execution of this generator. /// /// The argument will be passed into the coroutine as a resume argument. fn resume_with( self: Pin<&mut Self>, arg: Self::Resume, ) -> GeneratorState; } /// A trait implemented for generator types. /// /// This is modeled after the stdlib's nightly-only [`std::ops::Generator`]. pub trait Generator { /// The type of value this generator yields. type Yield; /// The type of value this generator returns upon completion. type Return; /// Resumes the execution of this generator. fn resume(self: Pin<&mut Self>) -> GeneratorState; } impl> Generator for C { type Yield = ::Yield; type Return = ::Return; #[must_use] fn resume(self: Pin<&mut Self>) -> GeneratorState { self.resume_with(()) } } /// The result of a generator resumption. /// /// This is modeled after the stdlib's nightly-only /// [`std::ops::GeneratorState`]. #[derive(PartialEq, Debug)] #[allow(clippy::module_name_repetitions)] pub enum GeneratorState { /// The generator suspended with a value. Yielded(Y), /// The generator completed with a return value. Complete(R), } genawaiter-0.99.1/src/rc/engine.rs000064400000000000000000000022731362207600500151410ustar0000000000000000use crate::{core, core::Next}; use std::{cell::Cell, rc::Rc}; pub struct Airlock(Rc>>); impl Default for Airlock { fn default() -> Self { Self(Rc::new(Cell::new(Next::Empty))) } } impl Clone for Airlock { fn clone(&self) -> Self { Self(self.0.clone()) } } impl core::Airlock for Airlock { type Yield = Y; type Resume = R; fn peek(&self) -> Next<(), ()> { // Safety: `Rc` is `!Send + !Sync`, and control does not leave this function // while the reference is taken, so concurrent access is not possible. The value // is not modified, so no shared references elsewhere can be invalidated. let inner = unsafe { &*self.0.as_ptr() }; inner.without_values() } fn replace(&self, next: Next) -> Next { self.0.replace(next) } } /// This object lets you yield values from the generator by calling the `yield_` /// method. /// /// "Co" can stand for either _controller_ or _coroutine_, depending on how /// theoretical you are feeling. /// /// [_See the module-level docs for examples._](.) pub type Co = core::Co>; genawaiter-0.99.1/src/rc/generator.rs000064400000000000000000000056641363127463700157040ustar0000000000000000use crate::{ core::{advance, async_advance, Airlock as _, Next}, ops::{Coroutine, GeneratorState}, rc::{engine::Airlock, Co}, }; use std::{future::Future, pin::Pin}; /// This is a generator which stores its state on the heap. /// /// [_See the module-level docs for examples._](.) pub struct Gen { airlock: Airlock, future: Pin>, } impl Gen { /// Creates a new generator from a function. /// /// The function accepts a [`Co`] object, and returns a future. Every time /// the generator is resumed, the future is polled. Each time the future is /// polled, it should do one of two things: /// /// - Call `co.yield_()`, and then return `Poll::Pending`. /// - Drop the `Co`, and then return `Poll::Ready`. /// /// Typically this exchange will happen in the context of an `async fn`. /// /// [_See the module-level docs for examples._](.) pub fn new(producer: impl FnOnce(Co) -> F) -> Self { let airlock = Airlock::default(); let future = { Box::pin(producer(Co::new(airlock.clone()))) }; Self { airlock, future } } /// Resumes execution of the generator. /// /// `arg` is the resume argument. If the generator was previously paused by /// awaiting a future returned from `co.yield()`, that future will complete, /// and return `arg`. /// /// If the generator yields a value, `Yielded` is returned. Otherwise, /// `Completed` is returned. /// /// [_See the module-level docs for examples._](.) pub fn resume_with(&mut self, arg: R) -> GeneratorState { self.airlock.replace(Next::Resume(arg)); advance(self.future.as_mut(), &self.airlock) } } impl Gen { /// Resumes execution of the generator. /// /// If the generator yields a value, `Yielded` is returned. Otherwise, /// `Completed` is returned. /// /// [_See the module-level docs for examples._](.) pub fn resume(&mut self) -> GeneratorState { self.resume_with(()) } /// Resumes execution of the generator. /// /// If the generator pauses without yielding, `Poll::Pending` is returned. /// If the generator yields a value, `Poll::Ready(Yielded)` is returned. /// Otherwise, `Poll::Ready(Completed)` is returned. /// /// [_See the module-level docs for examples._](.) pub fn async_resume( &mut self, ) -> impl Future> + '_ { self.airlock.replace(Next::Resume(())); async_advance(self.future.as_mut(), self.airlock.clone()) } } impl Coroutine for Gen { type Yield = Y; type Resume = R; type Return = F::Output; fn resume_with( mut self: Pin<&mut Self>, arg: R, ) -> GeneratorState { Self::resume_with(&mut *self, arg) } } genawaiter-0.99.1/src/rc/iterator.rs000064400000000000000000000022441362227527400155340ustar0000000000000000use crate::{ops::GeneratorState, rc::Gen}; use std::future::Future; impl> IntoIterator for Gen { type Item = Y; type IntoIter = IntoIter; #[must_use] fn into_iter(self) -> Self::IntoIter { IntoIter { generator: self } } } pub struct IntoIter> { generator: Gen, } impl> Iterator for IntoIter { type Item = Y; fn next(&mut self) -> Option { match self.generator.resume() { GeneratorState::Yielded(x) => Some(x), GeneratorState::Complete(()) => None, } } } #[cfg(test)] mod tests { use crate::rc::{Co, Gen}; use std::iter::IntoIterator; async fn produce(co: Co) { co.yield_(10).await; co.yield_(20).await; } #[test] fn into_iter() { let gen = Gen::new(produce); let items: Vec<_> = gen.into_iter().collect(); assert_eq!(items, [10, 20]); } #[test] fn for_loop() { let mut sum = 0; for x in Gen::new(produce) { sum += x; } assert_eq!(sum, 30); } } genawaiter-0.99.1/src/rc/mod.rs000064400000000000000000000274501362230240500144530ustar0000000000000000/*! This module implements a generator which stores its state on the heap. You can create a basic generator with [`gen!`] and [`yield_!`]. [`gen!`]: macro.gen.html ```rust # #[cfg(feature = "proc_macro")] # fn feature_gate() { # use genawaiter::{rc::gen, yield_}; # let mut my_generator = gen!({ yield_!(10); }); # my_generator.resume(); # } ``` If you need to reuse logic between multiple generators, you can define the logic with [`rc_producer!`] and [`yield_!`], and instantiate generators with [`Gen::new`]. ```rust # #[cfg(feature = "proc_macro")] # fn feature_gate() { # use genawaiter::{rc::Gen, rc_producer as producer, yield_}; # let my_producer = producer!({ yield_!(10); }); let mut my_generator = Gen::new(my_producer); # my_generator.resume(); # } ``` If you don't like macros, you can use the low-level API directly. ```rust # use genawaiter::rc::{Co, Gen}; # async fn my_producer(co: Co) { co.yield_(10).await; } let mut my_generator = Gen::new(my_producer); # my_generator.resume(); ``` # Examples ## Using `Iterator` Generators implement `Iterator`, so you can use them in a for loop: ```rust # #[cfg(feature = "proc_macro")] # fn feature_gate() { use genawaiter::{rc::gen, yield_}; let odds_under_ten = gen!({ let mut n = 1; while n < 10 { yield_!(n); n += 2; } }); # let mut test = Vec::new(); for num in odds_under_ten { println!("{}", num); # test.push(num); } # assert_eq!(test, [1, 3, 5, 7, 9]); # } ``` ## Collecting into a `Vec` ```rust # #[cfg(feature = "proc_macro")] # fn feature_gate() { # use genawaiter::{rc::gen, yield_}; # # let odds_under_ten = gen!({ # for n in (1..).step_by(2).take_while(|&n| n < 10) { yield_!(n); } # }); # let xs: Vec<_> = odds_under_ten.into_iter().collect(); assert_eq!(xs, [1, 3, 5, 7, 9]); # } ``` ## A generator is a closure Like any closure, you can capture values from outer scopes. ```rust # #[cfg(feature = "proc_macro")] # fn feature_gate() { # use genawaiter::{rc::gen, yield_, GeneratorState}; # let two = 2; let mut multiply = gen!({ yield_!(10 * two); }); assert_eq!(multiply.resume(), GeneratorState::Yielded(20)); # } ``` ## Using `resume()` ```rust # #[cfg(feature = "proc_macro")] # fn feature_gate() { # use genawaiter::{rc::gen, yield_, GeneratorState}; # # let mut odds_under_ten = gen!({ # for n in (1..).step_by(2).take_while(|&n| n < 10) { yield_!(n); } # }); # assert_eq!(odds_under_ten.resume(), GeneratorState::Yielded(1)); assert_eq!(odds_under_ten.resume(), GeneratorState::Yielded(3)); assert_eq!(odds_under_ten.resume(), GeneratorState::Yielded(5)); assert_eq!(odds_under_ten.resume(), GeneratorState::Yielded(7)); assert_eq!(odds_under_ten.resume(), GeneratorState::Yielded(9)); assert_eq!(odds_under_ten.resume(), GeneratorState::Complete(())); # } ``` ## Passing resume arguments You can pass values into the generator. Note that the first resume argument will be lost. This is because at the time the first value is sent, there is no future being awaited inside the generator, so there is no place the value could go where the generator could observe it. ```rust # #[cfg(feature = "proc_macro")] # fn feature_gate() { # use genawaiter::{rc::gen, yield_}; # let mut check_numbers = gen!({ let num = yield_!(()); assert_eq!(num, 1); let num = yield_!(()); assert_eq!(num, 2); }); check_numbers.resume_with(0); check_numbers.resume_with(1); check_numbers.resume_with(2); # } ``` ## Returning a completion value You can return a completion value with a different type than the values that are yielded. ```rust # #[cfg(feature = "proc_macro")] # fn feature_gate() { # use genawaiter::{rc::gen, yield_, GeneratorState}; # let mut numbers_then_string = gen!({ yield_!(10); yield_!(20); "done!" }); assert_eq!(numbers_then_string.resume(), GeneratorState::Yielded(10)); assert_eq!(numbers_then_string.resume(), GeneratorState::Yielded(20)); assert_eq!(numbers_then_string.resume(), GeneratorState::Complete("done!")); # } ``` ## Defining a reusable producer function ```rust # #[cfg(feature = "proc_macro")] # fn feature_gate() { # use genawaiter::{rc::{producer_fn, Gen}, yield_, GeneratorState}; # #[producer_fn(u8)] async fn produce() { yield_!(10); } let mut gen = Gen::new(produce); assert_eq!(gen.resume(), GeneratorState::Yielded(10)); # } ``` ## Defining a reusable producer closure ```rust # #[cfg(feature = "proc_macro")] # fn feature_gate() { # use genawaiter::{rc::Gen, yield_, GeneratorState}; use genawaiter::rc_producer as producer; let produce = producer!({ yield_!(10); }); let mut gen = Gen::new(produce); assert_eq!(gen.resume(), GeneratorState::Yielded(10)); # } ``` ## Using the low-level API You can define an `async fn` directly, instead of relying on the `gen!` or `producer!` macros. ```rust use genawaiter::rc::{Co, Gen}; async fn producer(co: Co) { let mut n = 1; while n < 10 { co.yield_(n).await; n += 2; } } let odds_under_ten = Gen::new(producer); let result: Vec<_> = odds_under_ten.into_iter().collect(); assert_eq!(result, [1, 3, 5, 7, 9]); ``` ## Using the low-level API with an async closure (nightly Rust only) ```ignore # use genawaiter::{rc::Gen, GeneratorState}; # let gen = Gen::new(async move |co| { co.yield_(10).await; co.yield_(20).await; }); assert_eq!(gen.resume(), GeneratorState::Yielded(10)); assert_eq!(gen.resume(), GeneratorState::Yielded(20)); assert_eq!(gen.resume(), GeneratorState::Complete(())); ``` ## Using the low-level API with an async closure faux·sure (for stable Rust) ``` # use genawaiter::{rc::Gen, GeneratorState}; # let mut gen = Gen::new(|co| async move { co.yield_(10).await; co.yield_(20).await; }); assert_eq!(gen.resume(), GeneratorState::Yielded(10)); assert_eq!(gen.resume(), GeneratorState::Yielded(20)); assert_eq!(gen.resume(), GeneratorState::Complete(())); ``` ## Using the low-level API with function arguments This is just ordinary Rust, nothing special. ```rust # use genawaiter::{rc::{Co, Gen}, GeneratorState}; # async fn multiples_of(num: i32, co: Co) { let mut cur = num; loop { co.yield_(cur).await; cur += num; } } let mut gen = Gen::new(|co| multiples_of(10, co)); assert_eq!(gen.resume(), GeneratorState::Yielded(10)); assert_eq!(gen.resume(), GeneratorState::Yielded(20)); assert_eq!(gen.resume(), GeneratorState::Yielded(30)); ``` */ pub use crate::rc::{engine::Co, generator::Gen}; /// Creates a generator. /// /// This macro takes one argument, which is the body of the generator. It should /// contain one or more calls to the [`yield_!`] macro. /// /// # Examples /// /// [_See the module-level docs for examples._](.) #[cfg(feature = "proc_macro")] pub use genawaiter_macro::rc_gen as gen; /// Turns a function into a producer, which can then be used to create a /// generator. /// /// The body of the function should contain one or more [`yield_!`] expressions. /// /// # Examples /// /// [_See the module-level docs for examples._](.) #[cfg(feature = "proc_macro")] pub use genawaiter_proc_macro::rc_producer_fn as producer_fn; mod engine; mod generator; mod iterator; #[cfg(feature = "futures03")] mod stream; #[cfg(feature = "nightly")] #[cfg(test)] mod nightly_tests; #[cfg(test)] mod tests { use crate::{ rc::{Co, Gen}, testing::DummyFuture, GeneratorState, }; use std::{ cell::{Cell, RefCell}, future::Future, }; async fn simple_producer(co: Co) -> &'static str { co.yield_(10).await; "done" } #[test] fn function() { let mut gen = Gen::new(simple_producer); assert_eq!(gen.resume(), GeneratorState::Yielded(10)); assert_eq!(gen.resume(), GeneratorState::Complete("done")); } #[test] fn simple_closure() { async fn gen(i: i32, co: Co) -> &'static str { co.yield_(i * 2).await; "done" } let mut gen = Gen::new(|co| gen(5, co)); assert_eq!(gen.resume(), GeneratorState::Yielded(10)); assert_eq!(gen.resume(), GeneratorState::Complete("done")); } #[test] fn resume_args() { async fn gen(resumes: &RefCell>, co: Co) { let resume_arg = co.yield_(10).await; resumes.borrow_mut().push(resume_arg); let resume_arg = co.yield_(20).await; resumes.borrow_mut().push(resume_arg); } let resumes = RefCell::new(Vec::new()); let mut gen = Gen::new(|co| gen(&resumes, co)); assert_eq!(*resumes.borrow(), &[] as &[&str]); assert_eq!(gen.resume_with("ignored"), GeneratorState::Yielded(10)); assert_eq!(*resumes.borrow(), &[] as &[&str]); assert_eq!(gen.resume_with("abc"), GeneratorState::Yielded(20)); assert_eq!(*resumes.borrow(), &["abc"]); assert_eq!(gen.resume_with("def"), GeneratorState::Complete(())); assert_eq!(*resumes.borrow(), &["abc", "def"]); } #[test] #[should_panic(expected = "non-async method")] fn forbidden_await_helpful_message() { async fn wrong(_: Co) { DummyFuture.await; } let mut gen = Gen::new(wrong); gen.resume(); } #[test] #[should_panic(expected = "Co::yield_")] fn multiple_yield_helpful_message() { async fn wrong(co: Co) { let _ = co.yield_(10); let _ = co.yield_(20); } let mut gen = Gen::new(wrong); gen.resume(); } #[test] #[should_panic = "should have been dropped by now"] fn escaped_co_helpful_message() { async fn shenanigans(co: Co) -> Co { co } let mut gen = Gen::new(shenanigans); let escaped_co = match gen.resume() { GeneratorState::Yielded(_) => panic!(), GeneratorState::Complete(co) => co, }; let _ = escaped_co.yield_(10); } /// This tests in a roundabout way that the `Gen` object can be moved. This /// should happen without moving the allocations inside so we don't /// segfault. #[test] fn gen_is_movable() { #[inline(never)] async fn produce(addrs: &mut Vec<*const i32>, co: Co) -> &'static str { let sentinel: Cell = Cell::new(0x8001); // If the future state moved, this reference would become invalid, and // hilarity would ensue. let sentinel_ref: &Cell = &sentinel; // Test a few times that `sentinel` and `sentinel_ref` point to the same // data. assert_eq!(sentinel.get(), 0x8001); sentinel_ref.set(0x8002); assert_eq!(sentinel.get(), 0x8002); addrs.push(sentinel.as_ptr()); co.yield_(10).await; assert_eq!(sentinel.get(), 0x8002); sentinel_ref.set(0x8003); assert_eq!(sentinel.get(), 0x8003); addrs.push(sentinel.as_ptr()); co.yield_(20).await; assert_eq!(sentinel.get(), 0x8003); sentinel_ref.set(0x8004); assert_eq!(sentinel.get(), 0x8004); addrs.push(sentinel.as_ptr()); "done" } /// Create a generator, resume it once (so `sentinel_ref` gets /// initialized), and then move it out of the function. fn create_generator( addrs: &mut Vec<*const i32>, ) -> Gen + '_> { let mut gen = Gen::new(move |co| produce(addrs, co)); assert_eq!(gen.resume(), GeneratorState::Yielded(10)); gen } let mut addrs = Vec::new(); let mut gen = create_generator(&mut addrs); assert_eq!(gen.resume(), GeneratorState::Yielded(20)); assert_eq!(gen.resume(), GeneratorState::Complete("done")); drop(gen); assert!(addrs.iter().all(|&p| p == addrs[0])); } } genawaiter-0.99.1/src/rc/nightly_tests.rs000064400000000000000000000006051362137101300165650ustar0000000000000000// These tests can't be parsed on non-nightly compilers, so move them to a // separate file. use crate::{ops::GeneratorState, rc::Gen}; #[test] fn async_closure() { let mut gen = Gen::new(async move |co| { co.yield_(10).await; "done" }); assert_eq!(gen.resume(), GeneratorState::Yielded(10)); assert_eq!(gen.resume(), GeneratorState::Complete("done")); } genawaiter-0.99.1/src/rc/stream.rs000064400000000000000000000027411362205756300151770ustar0000000000000000use crate::{ops::GeneratorState, rc::Gen}; use futures_core::{ task::{Context, Poll}, Stream, }; use std::{future::Future, pin::Pin}; impl> Stream for Gen { type Item = Y; fn poll_next( mut self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll> { let fut = self.async_resume(); pin_mut!(fut); match fut.poll(cx) { Poll::Ready(GeneratorState::Yielded(x)) => Poll::Ready(Some(x)), Poll::Ready(GeneratorState::Complete(())) => Poll::Ready(None), Poll::Pending => Poll::Pending, } } } #[cfg(test)] mod tests { use crate::{ rc::{Co, Gen}, testing::SlowFuture, }; use futures::{executor::block_on_stream, stream}; #[test] fn blocking() { async fn produce(co: Co) { co.yield_(10).await; co.yield_(20).await; } let gen = Gen::new(produce); let stream = stream::iter(gen); let items: Vec<_> = block_on_stream(stream).collect(); assert_eq!(items, [10, 20]); } #[test] fn non_blocking() { async fn produce(co: Co) { SlowFuture::new().await; co.yield_(10).await; SlowFuture::new().await; co.yield_(20).await; } let gen = Gen::new(produce); let items: Vec<_> = block_on_stream(gen).collect(); assert_eq!(items, [10, 20]); } } genawaiter-0.99.1/src/stack/engine.rs000064400000000000000000000025051362215512600156420ustar0000000000000000use crate::{core, core::Next}; use std::{cell::UnsafeCell, ptr}; /// This type holds the value that is pending being returned from the generator. /// /// # Safety /// /// This type is `!Sync` (so, single-thread), never exposed to user-land code, /// and never borrowed across a function call, so safety can be verified locally /// at each use site. pub struct Airlock(UnsafeCell>); impl Default for Airlock { fn default() -> Self { Self(UnsafeCell::new(Next::Empty)) } } impl<'s, Y, R> core::Airlock for &'s Airlock { type Yield = Y; type Resume = R; fn peek(&self) -> Next<(), ()> { // Safety: This follows the safety rules above. let inner = unsafe { &*self.0.get() }; inner.without_values() } fn replace( &self, next: Next, ) -> Next { // Safety: This follows the safety rules above. unsafe { ptr::replace(self.0.get(), next) } } } /// This object lets you yield values from the generator by calling the `yield_` /// method. /// /// "Co" can stand for either _controller_ or _coroutine_, depending on how /// theoretical you are feeling. /// /// [_See the module-level docs for examples._](.) pub type Co<'y, Y, R = ()> = core::Co<&'y Airlock>; genawaiter-0.99.1/src/stack/generator.rs000064400000000000000000000153441362225437700164000ustar0000000000000000use crate::{ core::{advance, async_advance, Airlock as _, Next}, ext::MaybeUninitExt, ops::{Coroutine, GeneratorState}, stack::engine::{Airlock, Co}, }; use std::{future::Future, mem, pin::Pin, ptr}; /// This data structure holds the transient state of an executing generator. /// /// It's called "Shelf", rather than "State", to avoid confusion with the /// `GeneratorState` enum. /// /// [_See the module-level docs for examples._](.) // Safety: The lifetime of the data is controlled by a `Gen`, which constructs // it in place, and holds a mutable reference right up until dropping it in // place. Thus, the data inside is pinned and can never be moved. pub struct Shelf(mem::MaybeUninit>); struct State { airlock: Airlock, future: F, } impl Shelf { /// Creates a new, empty `Shelf`. /// /// [_See the module-level docs for examples._](.) #[must_use] pub fn new() -> Self { Self(mem::MaybeUninit::uninit()) } } impl Default for Shelf { #[must_use] fn default() -> Self { Self::new() } } /// This is a generator which can be stack-allocated. /// /// [_See the module-level docs for examples._](.) pub struct Gen<'s, Y, R, F: Future> { state: Pin<&'s mut State>, } impl<'s, Y, R, F: Future> Gen<'s, Y, R, F> { /// Creates a new generator from a function. /// /// The state of the generator is stored in `shelf`, which will be pinned in /// place while this generator exists. The generator itself is movable, /// since it just holds a reference to the pinned state. /// /// The function accepts a [`Co`] object, and returns a future. Every time /// the generator is resumed, the future is polled. Each time the future is /// polled, it should do one of two things: /// /// - Call `co.yield_()`, and then return `Poll::Pending`. /// - Drop the `Co`, and then return `Poll::Ready`. /// /// Typically this exchange will happen in the context of an `async fn`. /// /// # Safety /// /// The `Co` object must not outlive the returned `Gen`. By time the /// generator completes (i.e., by time the producer's Future returns /// `Poll::Ready`), the `Co` object should already have been dropped. If /// this invariant is not upheld, memory unsafety can result. /// /// Afaik, the Rust compiler [is not flexible enough][hrtb-thread] to let /// you express this invariant in the type system, but I would love to be /// proven wrong! /// /// [hrtb-thread]: https://users.rust-lang.org/t/hrtb-on-multiple-generics/34255 /// /// # Examples /// /// ```rust /// # use genawaiter::stack::{Co, Gen, Shelf}; /// # /// # async fn producer(co: Co<'_, i32>) { /* ... */ } /// # /// let mut shelf = Shelf::new(); /// let gen = unsafe { Gen::new(&mut shelf, producer) }; /// ``` pub unsafe fn new( shelf: &'s mut Shelf, producer: impl FnOnce(Co<'s, Y, R>) -> F, ) -> Self { // Safety: Build the struct in place, by writing each field in place. let p = &mut *shelf.0.as_mut_ptr() as *mut State; let airlock = Airlock::default(); ptr::write(&mut (*p).airlock, airlock); let future = producer(Co::new(&(*p).airlock)); ptr::write(&mut (*p).future, future); // Safety: the state can never be moved again, because we store it inside a // `Pin` until `Gen::drop`, where the contents are dropped in place. let state = Pin::new_unchecked(shelf.0.assume_init_get_mut()); Self { state } } /// Resumes execution of the generator. /// /// `arg` is the resume argument. If the generator was previously paused by /// awaiting a future returned from `co.yield()`, that future will complete, /// and return `arg`. /// /// If the generator yields a value, `Yielded` is returned. Otherwise, /// `Completed` is returned. /// /// [_See the module-level docs for examples._](.) pub fn resume_with(&mut self, arg: R) -> GeneratorState { let (future, airlock) = self.project(); airlock.replace(Next::Resume(arg)); advance(future, &airlock) } fn project(&mut self) -> (Pin<&mut F>, &Airlock) { unsafe { // Safety: This is a pin projection. `future` is pinned, but never moved. // `airlock` is never pinned. let state = self.state.as_mut().get_unchecked_mut(); let future = Pin::new_unchecked(&mut state.future); let airlock = &state.airlock; (future, airlock) } } } impl<'s, Y, R, F: Future> Drop for Gen<'s, Y, R, F> { fn drop(&mut self) { // Safety: `state` is a `MaybeUninit` which is guaranteed to be initialized, // because the only way to construct a `Gen` is with `Gen::new`, which // initializes it. // // Drop `state` in place, by dropping each field in place. Drop `future` first, // since it likely contains a reference to `airlock` (through the `co` object). // Since we drop everything in place, the `Pin` invariants are not violated. unsafe { let state = self.state.as_mut().get_unchecked_mut(); ptr::drop_in_place(&mut state.future); ptr::drop_in_place(&mut state.airlock); } } } impl<'s, Y, F: Future> Gen<'s, Y, (), F> { /// Resumes execution of the generator. /// /// If the generator yields a value, `Yielded` is returned. Otherwise, /// `Completed` is returned. /// /// [_See the module-level docs for examples._](.) pub fn resume(&mut self) -> GeneratorState { self.resume_with(()) } /// Resumes execution of the generator. /// /// If the generator pauses without yielding, `Poll::Pending` is returned. /// If the generator yields a value, `Poll::Ready(Yielded)` is returned. /// Otherwise, `Poll::Ready(Completed)` is returned. /// /// [_See the module-level docs for examples._](.) pub fn async_resume( &mut self, ) -> impl Future> + '_ { let (future, airlock) = self.project(); airlock.replace(Next::Resume(())); async_advance(future, airlock) } } impl<'s, Y, R, F: Future> Coroutine for Gen<'s, Y, R, F> { type Yield = Y; type Resume = R; type Return = F::Output; fn resume_with( self: Pin<&mut Self>, arg: R, ) -> GeneratorState { // Safety: `Gen::resume_with` does not move `self`. let this = unsafe { self.get_unchecked_mut() }; this.resume_with(arg) } } genawaiter-0.99.1/src/stack/iterator.rs000064400000000000000000000046611362227541500162370ustar0000000000000000use crate::{ops::GeneratorState, stack::generator::Gen}; use std::future::Future; impl<'s, Y, F: Future> IntoIterator for Gen<'s, Y, (), F> { type Item = Y; type IntoIter = IntoIter<'s, Y, F>; #[must_use] fn into_iter(self) -> Self::IntoIter { IntoIter { generator: self } } } pub struct IntoIter<'s, Y, F: Future> { generator: Gen<'s, Y, (), F>, } impl<'s, Y, F: Future> Iterator for IntoIter<'s, Y, F> { type Item = Y; fn next(&mut self) -> Option { match self.generator.resume() { GeneratorState::Yielded(x) => Some(x), GeneratorState::Complete(()) => None, } } } impl<'r, 's, Y, F: Future> IntoIterator for &'r mut Gen<'s, Y, (), F> { type Item = Y; type IntoIter = MutIntoIter<'r, 's, Y, F>; fn into_iter(self) -> Self::IntoIter { MutIntoIter { generator: self } } } pub struct MutIntoIter<'r, 's, Y, F: Future> { generator: &'r mut Gen<'s, Y, (), F>, } impl<'r, 's, Y, F: Future> Iterator for MutIntoIter<'r, 's, Y, F> { type Item = Y; fn next(&mut self) -> Option { match self.generator.resume() { GeneratorState::Yielded(x) => Some(x), GeneratorState::Complete(()) => None, } } } #[cfg(test)] mod tests { use crate::stack::{let_gen_using, Co, Gen, Shelf}; use std::iter::IntoIterator; async fn produce(co: Co<'_, i32>) { co.yield_(10).await; co.yield_(20).await; } #[test] fn let_gen_using_into_iter() { let_gen_using!(gen, produce); let items: Vec<_> = gen.into_iter().collect(); assert_eq!(items, [10, 20]); } #[test] fn let_gen_using_for_loop() { let_gen_using!(gen, produce); let mut sum = 0; for x in gen { sum += x; } assert_eq!(sum, 30); } #[test] fn shelf_generator_into_iter() { let mut shelf = Shelf::new(); let gen = unsafe { Gen::new(&mut shelf, produce) }; let items: Vec<_> = gen.into_iter().collect(); assert_eq!(items, [10, 20]); } #[test] fn shelf_generator_for_loop() { let mut shelf = Shelf::new(); let gen = unsafe { Gen::new(&mut shelf, produce) }; let mut sum = 0; for x in gen { sum += x; } assert_eq!(sum, 30); } } genawaiter-0.99.1/src/stack/macros.rs000064400000000000000000000050571362227615100156700ustar0000000000000000/** Creates a generator on the stack. This macro is deprecated. Use [`let_gen!`] or [`let_gen_using!`] instead. [`let_gen!`]: stack/macro.let_gen.html [`let_gen_using!`]: stack/macro.let_gen_using.html */ #[macro_export] #[deprecated = "Use `let_gen_using!()` instead."] macro_rules! generator_mut { ($name:ident, $producer:expr $(,)?) => { $crate::stack::let_gen_using!($name, $producer); }; } /** Creates a generator on the stack unsafely. This macro is deprecated. Use [`let_gen!`] or [`let_gen_using!`] instead. [`let_gen!`]: stack/macro.let_gen.html [`let_gen_using!`]: stack/macro.let_gen_using.html */ #[macro_export] #[deprecated = "Use `let_gen_using!()` instead."] macro_rules! unsafe_create_generator { ($name:ident, $producer:expr $(,)?) => { let mut generator_state = $crate::stack::Shelf::new(); #[allow(unused_mut)] let mut $name = unsafe { $crate::stack::Gen::new(&mut generator_state, $producer) }; }; } #[cfg(test)] mod tests { use crate::{ ops::GeneratorState, stack::{Co, Gen, Shelf}, }; /// This test proves that `Gen::new` is actually unsafe. #[test] #[ignore = "compile-only test"] fn unsafety() { async fn shenanigans(co: Co<'_, i32>) -> Co<'_, i32> { co } let mut shelf = Shelf::new(); let mut gen = unsafe { Gen::new(&mut shelf, shenanigans) }; // Get the `co` out of the generator (don't try this at home). let escaped_co = match gen.resume() { GeneratorState::Yielded(_) => panic!(), GeneratorState::Complete(co) => co, }; // Drop the generator. This drops the airlock (inside the state), but `co` still // holds a reference to the airlock. drop(gen); // Now we're able to use an invalidated reference. let _ = escaped_co.yield_(10); } } #[allow(dead_code)] mod doctests { /** ```compile_fail use genawaiter::{stack::{let_gen_using, Co}, Generator}; async fn producer(co: Co<'_, i32>) {} fn create_generator() -> impl Generator { let_gen_using!(gen, producer); gen } ``` */ fn generator_cannot_escape() {} /** This test is exactly the same as above, but doesn't trigger the failure. ``` use genawaiter::{stack::{let_gen_using, Co}, Generator}; async fn producer(co: Co<'_, i32>) {} fn create_generator() { // -> impl Generator { let_gen_using!(gen, producer); // gen } ``` */ fn generator_cannot_escape_baseline() {} } genawaiter-0.99.1/src/stack/mod.rs000064400000000000000000000333211362230312500151460ustar0000000000000000/*! This module implements a generator which doesn't allocate. You can create a basic generator with [`let_gen!`] and [`yield_!`]. [`let_gen!`]: macro.let_gen.html ```rust # #[cfg(feature = "proc_macro")] # fn feature_gate() { # use genawaiter::{stack::let_gen, yield_}; # let_gen!(my_generator, { yield_!(10); }); # my_generator.resume(); # } ``` If you don't like macros, you can use the low-level API directly, though note that this requires you to trade away safety. ```rust # use genawaiter::stack::{Co, Gen, Shelf}; # async fn my_producer(co: Co<'_, u8>) { co.yield_(10).await; } let mut shelf = Shelf::new(); let mut my_generator = unsafe { Gen::new(&mut shelf, my_producer) }; # my_generator.resume(); ``` # Examples ## Using `Iterator` Generators implement `Iterator`, so you can use them in a for loop: ```rust # #[cfg(feature = "proc_macro")] # fn feature_gate() { use genawaiter::{stack::let_gen, yield_}; let_gen!(odds_under_ten, { let mut n = 1; while n < 10 { yield_!(n); n += 2; } }); # let mut test = Vec::new(); for num in odds_under_ten { println!("{}", num); # test.push(num); } # assert_eq!(test, [1, 3, 5, 7, 9]); # } ``` ## Collecting into a `Vec` ```rust # #[cfg(feature = "proc_macro")] # fn feature_gate() { # use genawaiter::{stack::let_gen, yield_}; # # let_gen!(odds_under_ten, { # for n in (1..).step_by(2).take_while(|&n| n < 10) { yield_!(n); } # }); # let xs: Vec<_> = odds_under_ten.into_iter().collect(); assert_eq!(xs, [1, 3, 5, 7, 9]); # } ``` ## A generator is a closure Like any closure, you can capture values from outer scopes. ```rust # #[cfg(feature = "proc_macro")] # fn feature_gate() { # use genawaiter::{stack::let_gen, yield_, GeneratorState}; # let two = 2; let_gen!(multiply, { yield_!(10 * two); }); assert_eq!(multiply.resume(), GeneratorState::Yielded(20)); # } ``` ## Using `resume()` ```rust # #[cfg(feature = "proc_macro")] # fn feature_gate() { # use genawaiter::{stack::let_gen, yield_, GeneratorState}; # # let_gen!(odds_under_ten, { # for n in (1..).step_by(2).take_while(|&n| n < 10) { yield_!(n); } # }); # assert_eq!(odds_under_ten.resume(), GeneratorState::Yielded(1)); assert_eq!(odds_under_ten.resume(), GeneratorState::Yielded(3)); assert_eq!(odds_under_ten.resume(), GeneratorState::Yielded(5)); assert_eq!(odds_under_ten.resume(), GeneratorState::Yielded(7)); assert_eq!(odds_under_ten.resume(), GeneratorState::Yielded(9)); assert_eq!(odds_under_ten.resume(), GeneratorState::Complete(())); # } ``` ## Passing resume arguments You can pass values into the generator. Note that the first resume argument will be lost. This is because at the time the first value is sent, there is no future being awaited inside the generator, so there is no place the value could go where the generator could observe it. ```rust # #[cfg(feature = "proc_macro")] # fn feature_gate() { # use genawaiter::{stack::let_gen, yield_}; # let_gen!(check_numbers, { let num = yield_!(()); assert_eq!(num, 1); let num = yield_!(()); assert_eq!(num, 2); }); check_numbers.resume_with(0); check_numbers.resume_with(1); check_numbers.resume_with(2); # } ``` ## Returning a completion value You can return a completion value with a different type than the values that are yielded. ```rust # #[cfg(feature = "proc_macro")] # fn feature_gate() { # use genawaiter::{stack::let_gen, yield_, GeneratorState}; # let_gen!(numbers_then_string, { yield_!(10); yield_!(20); "done!" }); assert_eq!(numbers_then_string.resume(), GeneratorState::Yielded(10)); assert_eq!(numbers_then_string.resume(), GeneratorState::Yielded(20)); assert_eq!(numbers_then_string.resume(), GeneratorState::Complete("done!")); # } ``` ## Defining a reusable producer function ```rust # #[cfg(feature = "proc_macro")] # fn feature_gate() { # use genawaiter::{stack::{let_gen_using, producer_fn}, yield_, GeneratorState}; # #[producer_fn(u8)] async fn produce() { yield_!(10); } let_gen_using!(gen, produce); assert_eq!(gen.resume(), GeneratorState::Yielded(10)); # } ``` ## Using the low-level API You can define an `async fn` directly, instead of relying on the `gen!` or `producer!` macros. ```rust use genawaiter::stack::{let_gen_using, Co}; async fn producer(co: Co<'_, i32>) { let mut n = 1; while n < 10 { co.yield_(n).await; n += 2; } } let_gen_using!(odds_under_ten, producer); let result: Vec<_> = odds_under_ten.into_iter().collect(); assert_eq!(result, [1, 3, 5, 7, 9]); ``` ## Using the low-level API with an async closure (nightly Rust only) ```ignore # use genawaiter::{stack::let_gen_using, GeneratorState}; # let_gen_using!(gen, async move |co| { co.yield_(10).await; co.yield_(20).await; }); assert_eq!(gen.resume(), GeneratorState::Yielded(10)); assert_eq!(gen.resume(), GeneratorState::Yielded(20)); assert_eq!(gen.resume(), GeneratorState::Complete(())); ``` ## Using the low-level API with an async closure faux·sure (for stable Rust) ``` # use genawaiter::{stack::let_gen_using, GeneratorState}; # let_gen_using!(gen, |co| async move { co.yield_(10).await; co.yield_(20).await; }); assert_eq!(gen.resume(), GeneratorState::Yielded(10)); assert_eq!(gen.resume(), GeneratorState::Yielded(20)); assert_eq!(gen.resume(), GeneratorState::Complete(())); ``` ## Using the low-level API with function arguments This is just ordinary Rust, nothing special. ```rust # use genawaiter::{stack::{let_gen_using, Co}, GeneratorState}; # async fn multiples_of(num: i32, co: Co<'_, i32>) { let mut cur = num; loop { co.yield_(cur).await; cur += num; } } let_gen_using!(gen, |co| multiples_of(10, co)); assert_eq!(gen.resume(), GeneratorState::Yielded(10)); assert_eq!(gen.resume(), GeneratorState::Yielded(20)); assert_eq!(gen.resume(), GeneratorState::Yielded(30)); ``` */ pub use crate::stack::{ engine::Co, generator::{Gen, Shelf}, }; /// Creates a generator. /// /// The first argument is the name of the resulting variable. /// /// ```ignore /// let_gen!(my_generator, { /* ... */ }); /// // Think of this as the spiritual equivalent of: /// let mut my_generator = Gen::new(/* ... */); /// ``` /// /// The second argument is the body of the generator. It should contain one or /// more calls to the [`yield_!`] macro. /// /// This macro is a shortcut for creating both a generator and its backing state /// (called a [`Shelf`](struct.Shelf.html)). If you (or your IDE) dislike /// macros, you can also do the bookkeeping by hand by using /// [`Gen::new`](struct.Gen.html#method.new), though note that this requires you /// to trade away safety. /// /// # Examples /// /// [_See the module-level docs for examples._](.) #[cfg(feature = "proc_macro")] pub use genawaiter_macro::stack_let_gen as let_gen; /// Creates a generator using a producer defined elsewhere. /// /// The first argument is the name of the resulting variable. /// /// ```ignore /// let_gen!(my_generator, { /* ... */ }); /// // Think of this as the spiritual equivalent of: /// let mut my_generator = Gen::new(/* ... */); /// ``` /// /// The second line is the producer that will be used. It can be one of these /// two things: /// /// 1. The result of [`stack_producer!`] or [`stack_producer_fn!`] /// /// [`stack_producer_fn!`]: attr.producer_fn.html /// /// 2. A function with this type: /// /// ```ignore /// async fn producer(co: Co<'_, Yield, Resume>) -> Completion { /* ... */ } /// // which is equivalent to: /// fn producer(co: Co<'_, Yield, Resume>) -> impl Future { /* ... */ } /// ``` /// /// This macro is a shortcut for creating both a generator and its backing state /// (called a [`Shelf`](struct.Shelf.html)). If you (or your IDE) dislike /// macros, you can also do the bookkeeping by hand by using /// [`Gen::new`](struct.Gen.html#method.new), though note that this requires you /// to trade away safety. /// /// # Examples /// /// [_See the module-level docs for examples._](.) pub use genawaiter_macro::stack_let_gen_using as let_gen_using; /// Turns a function into a producer, which can then be used to create a /// generator. /// /// The body of the function should contain one or more [`yield_!`] expressions. /// /// # Examples /// /// [_See the module-level docs for examples._](.) #[cfg(feature = "proc_macro")] pub use genawaiter_proc_macro::stack_producer_fn as producer_fn; #[macro_use] mod macros; mod engine; mod generator; mod iterator; #[cfg(feature = "futures03")] mod stream; #[cfg(feature = "nightly")] #[cfg(test)] mod nightly_tests; #[cfg(test)] mod tests { use crate::{ stack::{let_gen_using, Co}, testing::DummyFuture, GeneratorState, }; use std::{ cell::RefCell, sync::{ atomic::{AtomicBool, Ordering}, Arc, }, }; async fn simple_producer(co: Co<'_, i32>) -> &'static str { co.yield_(10).await; "done" } #[test] fn function() { let_gen_using!(gen, simple_producer); assert_eq!(gen.resume(), GeneratorState::Yielded(10)); assert_eq!(gen.resume(), GeneratorState::Complete("done")); } #[test] fn simple_closure() { async fn gen(i: i32, co: Co<'_, i32>) -> &'static str { co.yield_(i * 2).await; "done" } let_gen_using!(gen, |co| gen(5, co)); assert_eq!(gen.resume(), GeneratorState::Yielded(10)); assert_eq!(gen.resume(), GeneratorState::Complete("done")); } #[test] fn resume_args() { async fn gen(resumes: &RefCell>, co: Co<'_, i32, &'static str>) { let resume_arg = co.yield_(10).await; resumes.borrow_mut().push(resume_arg); let resume_arg = co.yield_(20).await; resumes.borrow_mut().push(resume_arg); } let resumes = RefCell::new(Vec::new()); let_gen_using!(gen, |co| gen(&resumes, co)); assert_eq!(*resumes.borrow(), &[] as &[&str]); assert_eq!(gen.resume_with("ignored"), GeneratorState::Yielded(10)); assert_eq!(*resumes.borrow(), &[] as &[&str]); assert_eq!(gen.resume_with("abc"), GeneratorState::Yielded(20)); assert_eq!(*resumes.borrow(), &["abc"]); assert_eq!(gen.resume_with("def"), GeneratorState::Complete(())); assert_eq!(*resumes.borrow(), &["abc", "def"]); } #[test] #[should_panic(expected = "non-async method")] fn forbidden_await_helpful_message() { async fn wrong(_: Co<'_, i32>) { DummyFuture.await; } let_gen_using!(gen, wrong); gen.resume(); } #[test] #[should_panic(expected = "Co::yield_")] fn multiple_yield_helpful_message() { async fn wrong(co: Co<'_, i32>) { let _ = co.yield_(10); let _ = co.yield_(20); } let_gen_using!(gen, wrong); gen.resume(); } #[test] #[should_panic = "should have been dropped by now"] fn escaped_co_helpful_message() { async fn shenanigans(co: Co<'_, i32>) -> Co<'_, i32> { co } let_gen_using!(gen, shenanigans); let escaped_co = match gen.resume() { GeneratorState::Yielded(_) => panic!(), GeneratorState::Complete(co) => co, }; let _ = escaped_co.yield_(10); } /// Test the unsafe `Gen::drop` implementation. #[test] fn test_gen_drop() { struct SetFlagOnDrop(Arc); impl Drop for SetFlagOnDrop { fn drop(&mut self) { self.0.store(true, Ordering::SeqCst); } } let flag = Arc::new(AtomicBool::new(false)); { let capture_the_flag = flag.clone(); let_gen_using!(gen, |co| { async move { let _set_on_drop = SetFlagOnDrop(capture_the_flag); co.yield_(10).await; // We will never make it this far. unreachable!(); } }); assert_eq!(gen.resume(), GeneratorState::Yielded(10)); // `gen` is only a reference to the generator, and dropping a reference has // no effect. The underlying generator is hidden behind macro hygiene and so // cannot be dropped early. #[allow(clippy::drop_ref)] drop(gen); assert_eq!(flag.load(Ordering::SeqCst), false); } // After the block above ends, the generator goes out of scope and is dropped, // which drops the incomplete future, which drops `_set_on_drop`, which sets the // flag. assert_eq!(flag.load(Ordering::SeqCst), true); } } #[allow(dead_code)] mod doctests { /** Make sure `co` cannot escape to the `'static` lifetime. ```compile_fail use genawaiter::stack::{let_gen_using, Co}; async fn producer(co: Co<'static, i32>) {} let_gen_using!(gen, producer); ``` */ fn co_is_not_static() {} /** This test is exactly the same as above, but doesn't trigger the failure. ``` use genawaiter::stack::{let_gen_using, Co}; async fn producer(co: Co<'_, i32>) {} let_gen_using!(gen, producer); ``` */ fn co_is_not_static_baseline() {} } #[allow(dead_code)] #[cfg(feature = "proc_macro")] mod doc_compile_fail { /** Make sure `co` cannot be used as argument by user. ```compile_fail use genawaiter::{stack::{producer_fn, Co}, yield_}; #[producer_fn(u8)] async fn odds(co: Co<'_, u8>) { yield_!(10); } ``` */ fn with_args_compile_fail() {} /** This test is exactly the same as above, except it passes. ```rust use genawaiter::{stack::{producer_fn, Co}, yield_}; #[producer_fn(u8)] async fn odds() { yield_!(10); } ``` */ fn with_args_compile_fail_baseline() {} } genawaiter-0.99.1/src/stack/nightly_tests.rs000064400000000000000000000006171362211532300172720ustar0000000000000000// These tests can't be parsed on non-nightly compilers, so move them to a // separate file. use crate::{ops::GeneratorState, stack::let_gen_using}; #[test] fn async_closure() { let_gen_using!(gen, async move |co| { co.yield_(10).await; "done" }); assert_eq!(gen.resume(), GeneratorState::Yielded(10)); assert_eq!(gen.resume(), GeneratorState::Complete("done")); } genawaiter-0.99.1/src/stack/stream.rs000064400000000000000000000030031362206657000156660ustar0000000000000000use crate::{ops::GeneratorState, stack::Gen}; use futures_core::{ task::{Context, Poll}, Stream, }; use std::{future::Future, pin::Pin}; impl<'s, Y, F: Future> Stream for Gen<'s, Y, (), F> { type Item = Y; fn poll_next( mut self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll> { let fut = self.async_resume(); pin_mut!(fut); match fut.poll(cx) { Poll::Ready(GeneratorState::Yielded(x)) => Poll::Ready(Some(x)), Poll::Ready(GeneratorState::Complete(())) => Poll::Ready(None), Poll::Pending => Poll::Pending, } } } #[cfg(test)] mod tests { use crate::{ stack::{let_gen_using, Co}, testing::SlowFuture, }; use futures::{executor::block_on_stream, stream}; #[test] fn blocking() { async fn produce(co: Co<'_, i32>) { co.yield_(10).await; co.yield_(20).await; } let_gen_using!(gen, produce); let stream = stream::iter(gen); let items: Vec<_> = block_on_stream(stream).collect(); assert_eq!(items, [10, 20]); } #[test] fn non_blocking() { async fn produce(co: Co<'_, i32>) { SlowFuture::new().await; co.yield_(10).await; SlowFuture::new().await; co.yield_(20).await; } let_gen_using!(gen, produce); let items: Vec<_> = block_on_stream(gen).collect(); assert_eq!(items, [10, 20]); } } genawaiter-0.99.1/src/sync/boxed.rs000064400000000000000000000045171362215455100153530ustar0000000000000000use crate::sync::{Co, Gen}; use std::{future::Future, pin::Pin}; /// This is a type alias for generators which can be stored in a `'static`. It's /// only really needed to help the compiler's type inference along. #[allow(clippy::module_name_repetitions)] pub type GenBoxed = Gen + Send>>>; impl GenBoxed { /// Creates a new generator with a boxed future, so it can be stored in a /// `static`. /// /// This works exactly the same as [`Gen::new`](struct.Gen.html#method.new) /// with an immediately boxed future. /// /// This method exists solely to help the compiler with type inference. /// These two lines are equivalent, except that the compiler cannot infer /// the correct type on the second line: /// /// ```compile_fail /// # use genawaiter::sync::{Co, Gen, GenBoxed}; /// # use std::{future::Future, pin::Pin}; /// # /// # async fn producer(co: Co) { /// # for n in (1..).step_by(2).take_while(|&n| n < 10) { co.yield_(n).await; } /// # } /// # /// let _: GenBoxed = Gen::new_boxed(|co| producer(co)); /// let _: GenBoxed = Gen::new(|co| Box::pin(producer(co))); /// ``` pub fn new_boxed(producer: impl FnOnce(Co) -> F) -> Self where F: Future + Send + 'static, { Self::new(|co| Box::pin(producer(co))) } } #[cfg(test)] mod tests { use crate::{ ops::GeneratorState, sync::{Co, Gen}, }; use std::sync::{Arc, Mutex}; async fn odd_numbers_less_than_ten(co: Co) { for n in (1..).step_by(2).take_while(|&n| n < 10) { co.yield_(n).await; } } #[test] fn can_be_stored_in_static() { let gen = Gen::new_boxed(odd_numbers_less_than_ten); // `T` must be `Send` for `Mutex` to be `Send + Sync`. let _: &dyn Send = &gen; let arc = Arc::new(Mutex::new(gen)); // A type must be `Sync` to be stored in a `static`. (In this particular case, // this is the case for `Arc>` if `Gen<...>` is `Send`. let _: &dyn Sync = &arc; let mut guard = arc.lock().unwrap(); assert_eq!(guard.resume(), GeneratorState::Yielded(1)); assert_eq!(guard.resume(), GeneratorState::Yielded(3)); } } genawaiter-0.99.1/src/sync/engine.rs000064400000000000000000000017111362207603600155110ustar0000000000000000use crate::{core, core::Next}; use std::{ mem, sync::{Arc, Mutex}, }; pub struct Airlock(Arc>>); impl Default for Airlock { fn default() -> Self { Self(Arc::new(Mutex::new(Next::Empty))) } } impl Clone for Airlock { fn clone(&self) -> Self { Self(self.0.clone()) } } impl core::Airlock for Airlock { type Yield = Y; type Resume = R; fn peek(&self) -> Next<(), ()> { self.0.lock().unwrap().without_values() } fn replace(&self, next: Next) -> Next { mem::replace(&mut self.0.lock().unwrap(), next) } } /// This object lets you yield values from the generator by calling the `yield_` /// method. /// /// "Co" can stand for either _controller_ or _coroutine_, depending on how /// theoretical you are feeling. /// /// [_See the module-level docs for examples._](.) pub type Co = core::Co>; genawaiter-0.99.1/src/sync/generator.rs000064400000000000000000000056671362211715100162420ustar0000000000000000use crate::{ core::{advance, async_advance, Airlock as _, Next}, ops::{Coroutine, GeneratorState}, sync::{engine::Airlock, Co}, }; use std::{future::Future, pin::Pin}; /// This is a generator which can be shared between threads. /// /// [_See the module-level docs for examples._](.) pub struct Gen { airlock: Airlock, future: Pin>, } impl Gen { /// Creates a new generator from a function. /// /// The function accepts a [`Co`] object, and returns a future. Every time /// the generator is resumed, the future is polled. Each time the future is /// polled, it should do one of two things: /// /// - Call `co.yield_()`, and then return `Poll::Pending`. /// - Drop the `Co`, and then return `Poll::Ready`. /// /// Typically this exchange will happen in the context of an `async fn`. /// /// [_See the module-level docs for examples._](.) pub fn new(producer: impl FnOnce(Co) -> F) -> Self { let airlock = Airlock::default(); let future = { Box::pin(producer(Co::new(airlock.clone()))) }; Self { airlock, future } } /// Resumes execution of the generator. /// /// `arg` is the resume argument. If the generator was previously paused by /// awaiting a future returned from `co.yield()`, that future will complete, /// and return `arg`. /// /// If the generator yields a value, `Yielded` is returned. Otherwise, /// `Completed` is returned. /// /// [_See the module-level docs for examples._](.) pub fn resume_with(&mut self, arg: R) -> GeneratorState { self.airlock.replace(Next::Resume(arg)); advance(self.future.as_mut(), &self.airlock) } } impl Gen { /// Resumes execution of the generator. /// /// If the generator yields a value, `Yielded` is returned. Otherwise, /// `Completed` is returned. /// /// [_See the module-level docs for examples._](.) pub fn resume(&mut self) -> GeneratorState { self.resume_with(()) } /// Resumes execution of the generator. /// /// If the generator pauses without yielding, `Poll::Pending` is returned. /// If the generator yields a value, `Poll::Ready(Yielded)` is returned. /// Otherwise, `Poll::Ready(Completed)` is returned. /// /// [_See the module-level docs for examples._](.) pub fn async_resume( &mut self, ) -> impl Future> + '_ { self.airlock.replace(Next::Resume(())); async_advance(self.future.as_mut(), self.airlock.clone()) } } impl Coroutine for Gen { type Yield = Y; type Resume = R; type Return = F::Output; fn resume_with( mut self: Pin<&mut Self>, arg: R, ) -> GeneratorState { Self::resume_with(&mut *self, arg) } } genawaiter-0.99.1/src/sync/iterator.rs000064400000000000000000000022501362227531300160730ustar0000000000000000use crate::{ops::GeneratorState, sync::Gen}; use std::future::Future; impl> IntoIterator for Gen { type Item = Y; type IntoIter = IntoIter; #[must_use] fn into_iter(self) -> Self::IntoIter { IntoIter { generator: self } } } pub struct IntoIter> { generator: Gen, } impl> Iterator for IntoIter { type Item = Y; fn next(&mut self) -> Option { match self.generator.resume() { GeneratorState::Yielded(x) => Some(x), GeneratorState::Complete(()) => None, } } } #[cfg(test)] mod tests { use crate::sync::{Co, Gen}; use std::iter::IntoIterator; async fn produce(co: Co) { co.yield_(10).await; co.yield_(20).await; } #[test] fn into_iter() { let gen = Gen::new(produce); let items: Vec<_> = gen.into_iter().collect(); assert_eq!(items, [10, 20]); } #[test] fn for_loop() { let mut sum = 0; for x in Gen::new(produce) { sum += x; } assert_eq!(sum, 30); } } genawaiter-0.99.1/src/sync/mod.rs000064400000000000000000000332411362230315600150220ustar0000000000000000/*! This module implements a generator which can be shared between threads. You can create a basic generator with [`gen!`] and [`yield_!`]. [`gen!`]: macro.gen.html ```rust # #[cfg(feature = "proc_macro")] # fn feature_gate() { # use genawaiter::{sync::gen, yield_}; # let mut my_generator = gen!({ yield_!(10); }); # my_generator.resume(); # } ``` If you need to reuse logic between multiple generators, you can define the logic with [`sync_producer!`] and [`yield_!`], and instantiate generators with [`Gen::new`]. ```rust # #[cfg(feature = "proc_macro")] # fn feature_gate() { # use genawaiter::{sync::Gen, sync_producer as producer, yield_}; # let my_producer = producer!({ yield_!(10); }); let mut my_generator = Gen::new(my_producer); # my_generator.resume(); # } ``` If you don't like macros, you can use the low-level API directly. ```rust # use genawaiter::sync::{Co, Gen}; # async fn my_producer(co: Co) { co.yield_(10).await; } let mut my_generator = Gen::new(my_producer); # my_generator.resume(); ``` # Storing a generator in a `static` In Rust, the type of static variables must be nameable, but the type of an `async fn` is not nameable – `async fn`s always return `impl Future`. So, in order to store a generator in a static, you'll need `dyn Future`, plus a layer of indirection. This crate provides the [`GenBoxed`](type.GenBoxed.html) type alias with the [`Gen::new_boxed`](type.GenBoxed.html#method.new_boxed) function to make this easier (and to smooth out a rough corner in the type inference). Additionally, as usual when dealing with statics in Rust, you'll need some form of synchronization. Here is one possible pattern, using the [`once_cell`] crate. [`once_cell`]: https://crates.io/crates/once_cell ``` # #[cfg(feature = "proc_macro")] # fn feature_gate() { use genawaiter::{sync::{Gen, GenBoxed}, sync_producer as producer, yield_}; use once_cell::sync::Lazy; use std::sync::Mutex; static INEFFICIENT_COUNTER: Lazy>> = Lazy::new(|| Mutex::new(Gen::new_boxed(producer!({ let mut n = 0; loop { n += 1; yield_!(n); } })))); # } ``` # Examples ## Using `Iterator` Generators implement `Iterator`, so you can use them in a for loop: ```rust # #[cfg(feature = "proc_macro")] # fn feature_gate() { use genawaiter::{sync::gen, yield_}; let odds_under_ten = gen!({ let mut n = 1; while n < 10 { yield_!(n); n += 2; } }); # let mut test = Vec::new(); for num in odds_under_ten { println!("{}", num); # test.push(num); } # assert_eq!(test, [1, 3, 5, 7, 9]); # } ``` ## Collecting into a `Vec` ```rust # #[cfg(feature = "proc_macro")] # fn feature_gate() { # use genawaiter::{sync::gen, yield_}; # # let odds_under_ten = gen!({ # for n in (1..).step_by(2).take_while(|&n| n < 10) { yield_!(n); } # }); # let xs: Vec<_> = odds_under_ten.into_iter().collect(); assert_eq!(xs, [1, 3, 5, 7, 9]); # } ``` ## A generator is a closure Like any closure, you can capture values from outer scopes. ```rust # #[cfg(feature = "proc_macro")] # fn feature_gate() { # use genawaiter::{sync::gen, yield_, GeneratorState}; # let two = 2; let mut multiply = gen!({ yield_!(10 * two); }); assert_eq!(multiply.resume(), GeneratorState::Yielded(20)); # } ``` ## Using `resume()` ```rust # #[cfg(feature = "proc_macro")] # fn feature_gate() { # use genawaiter::{sync::gen, yield_, GeneratorState}; # # let mut odds_under_ten = gen!({ # for n in (1..).step_by(2).take_while(|&n| n < 10) { yield_!(n); } # }); # assert_eq!(odds_under_ten.resume(), GeneratorState::Yielded(1)); assert_eq!(odds_under_ten.resume(), GeneratorState::Yielded(3)); assert_eq!(odds_under_ten.resume(), GeneratorState::Yielded(5)); assert_eq!(odds_under_ten.resume(), GeneratorState::Yielded(7)); assert_eq!(odds_under_ten.resume(), GeneratorState::Yielded(9)); assert_eq!(odds_under_ten.resume(), GeneratorState::Complete(())); # } ``` ## Passing resume arguments You can pass values into the generator. Note that the first resume argument will be lost. This is because at the time the first value is sent, there is no future being awaited inside the generator, so there is no place the value could go where the generator could observe it. ```rust # #[cfg(feature = "proc_macro")] # fn feature_gate() { # use genawaiter::{sync::gen, yield_}; # let mut check_numbers = gen!({ let num = yield_!(()); assert_eq!(num, 1); let num = yield_!(()); assert_eq!(num, 2); }); check_numbers.resume_with(0); check_numbers.resume_with(1); check_numbers.resume_with(2); # } ``` ## Returning a completion value You can return a completion value with a different type than the values that are yielded. ```rust # #[cfg(feature = "proc_macro")] # fn feature_gate() { # use genawaiter::{sync::gen, yield_, GeneratorState}; # let mut numbers_then_string = gen!({ yield_!(10); yield_!(20); "done!" }); assert_eq!(numbers_then_string.resume(), GeneratorState::Yielded(10)); assert_eq!(numbers_then_string.resume(), GeneratorState::Yielded(20)); assert_eq!(numbers_then_string.resume(), GeneratorState::Complete("done!")); # } ``` ## Defining a reusable producer function ```rust # #[cfg(feature = "proc_macro")] # fn feature_gate() { # use genawaiter::{sync::{producer_fn, Gen}, yield_, GeneratorState}; # #[producer_fn(u8)] async fn produce() { yield_!(10); } let mut gen = Gen::new(produce); assert_eq!(gen.resume(), GeneratorState::Yielded(10)); # } ``` ## Defining a reusable producer closure ```rust # #[cfg(feature = "proc_macro")] # fn feature_gate() { # use genawaiter::{sync::Gen, yield_, GeneratorState}; use genawaiter::sync_producer as producer; let produce = producer!({ yield_!(10); }); let mut gen = Gen::new(produce); assert_eq!(gen.resume(), GeneratorState::Yielded(10)); # } ``` ## Using the low-level API You can define an `async fn` directly, instead of relying on the `gen!` or `producer!` macros. ```rust use genawaiter::sync::{Co, Gen}; async fn producer(co: Co) { let mut n = 1; while n < 10 { co.yield_(n).await; n += 2; } } let odds_under_ten = Gen::new(producer); let result: Vec<_> = odds_under_ten.into_iter().collect(); assert_eq!(result, [1, 3, 5, 7, 9]); ``` ## Using the low-level API with an async closure (nightly Rust only) ```ignore # use genawaiter::{sync::Gen, GeneratorState}; # let gen = Gen::new(async move |co| { co.yield_(10).await; co.yield_(20).await; }); assert_eq!(gen.resume(), GeneratorState::Yielded(10)); assert_eq!(gen.resume(), GeneratorState::Yielded(20)); assert_eq!(gen.resume(), GeneratorState::Complete(())); ``` ## Using the low-level API with an async closure faux·sure (for stable Rust) ``` # use genawaiter::{sync::Gen, GeneratorState}; # let mut gen = Gen::new(|co| async move { co.yield_(10).await; co.yield_(20).await; }); assert_eq!(gen.resume(), GeneratorState::Yielded(10)); assert_eq!(gen.resume(), GeneratorState::Yielded(20)); assert_eq!(gen.resume(), GeneratorState::Complete(())); ``` ## Using the low-level API with function arguments This is just ordinary Rust, nothing special. ```rust # use genawaiter::{sync::{Co, Gen}, GeneratorState}; # async fn multiples_of(num: i32, co: Co) { let mut cur = num; loop { co.yield_(cur).await; cur += num; } } let mut gen = Gen::new(|co| multiples_of(10, co)); assert_eq!(gen.resume(), GeneratorState::Yielded(10)); assert_eq!(gen.resume(), GeneratorState::Yielded(20)); assert_eq!(gen.resume(), GeneratorState::Yielded(30)); ``` */ pub use crate::sync::{boxed::GenBoxed, engine::Co, generator::Gen}; /// Creates a generator. /// /// This macro takes one argument, which is the body of the generator. It should /// contain one or more calls to the [`yield_!`] macro. /// /// # Examples /// /// [_See the module-level docs for examples._](.) #[cfg(feature = "proc_macro")] pub use genawaiter_macro::sync_gen as gen; /// Turns a function into a producer, which can then be used to create a /// generator. /// /// The body of the function should contain one or more [`yield_!`] expressions. /// /// # Examples /// /// [_See the module-level docs for examples._](.) #[cfg(feature = "proc_macro")] pub use genawaiter_proc_macro::sync_producer_fn as producer_fn; mod boxed; mod engine; mod generator; mod iterator; #[cfg(feature = "futures03")] mod stream; #[cfg(feature = "nightly")] #[cfg(test)] mod nightly_tests; #[cfg(test)] mod tests { use crate::{ sync::{Co, Gen}, testing::{DummyFuture, SlowFuture}, GeneratorState, }; use futures::executor::block_on; use std::{ cell::{Cell, RefCell}, future::Future, }; async fn simple_producer(co: Co) -> &'static str { co.yield_(10).await; "done" } #[test] fn function() { let mut gen = Gen::new(simple_producer); assert_eq!(gen.resume(), GeneratorState::Yielded(10)); assert_eq!(gen.resume(), GeneratorState::Complete("done")); } #[test] fn simple_closure() { async fn gen(i: i32, co: Co) -> &'static str { co.yield_(i * 2).await; "done" } let mut gen = Gen::new(|co| gen(5, co)); assert_eq!(gen.resume(), GeneratorState::Yielded(10)); assert_eq!(gen.resume(), GeneratorState::Complete("done")); } #[test] fn resume_args() { async fn gen(resumes: &RefCell>, co: Co) { let resume_arg = co.yield_(10).await; resumes.borrow_mut().push(resume_arg); let resume_arg = co.yield_(20).await; resumes.borrow_mut().push(resume_arg); } let resumes = RefCell::new(Vec::new()); let mut gen = Gen::new(|co| gen(&resumes, co)); assert_eq!(*resumes.borrow(), &[] as &[&str]); assert_eq!(gen.resume_with("ignored"), GeneratorState::Yielded(10)); assert_eq!(*resumes.borrow(), &[] as &[&str]); assert_eq!(gen.resume_with("abc"), GeneratorState::Yielded(20)); assert_eq!(*resumes.borrow(), &["abc"]); assert_eq!(gen.resume_with("def"), GeneratorState::Complete(())); assert_eq!(*resumes.borrow(), &["abc", "def"]); } #[test] fn async_resume() { async fn produce(co: Co) { SlowFuture::new().await; co.yield_(10).await; SlowFuture::new().await; co.yield_(20).await; } async fn run_test() { let mut gen = Gen::new(produce); let x = gen.async_resume().await; assert_eq!(x, GeneratorState::Yielded(10)); let x = gen.async_resume().await; assert_eq!(x, GeneratorState::Yielded(20)); let x = gen.async_resume().await; assert_eq!(x, GeneratorState::Complete(())); } block_on(run_test()); } #[test] #[should_panic(expected = "non-async method")] fn forbidden_await_helpful_message() { async fn wrong(_: Co) { DummyFuture.await; } let mut gen = Gen::new(wrong); gen.resume(); } #[test] #[should_panic(expected = "Co::yield_")] fn multiple_yield_helpful_message() { async fn wrong(co: Co) { let _ = co.yield_(10); let _ = co.yield_(20); } let mut gen = Gen::new(wrong); gen.resume(); } #[test] #[should_panic = "should have been dropped by now"] fn escaped_co_helpful_message() { async fn shenanigans(co: Co) -> Co { co } let mut gen = Gen::new(shenanigans); let escaped_co = match gen.resume() { GeneratorState::Yielded(_) => panic!(), GeneratorState::Complete(co) => co, }; let _ = escaped_co.yield_(10); } /// This tests in a roundabout way that the `Gen` object can be moved. This /// should happen without moving the allocations inside so we don't /// segfault. #[test] fn gen_is_movable() { #[inline(never)] async fn produce(addrs: &mut Vec<*const i32>, co: Co) -> &'static str { let sentinel: Cell = Cell::new(0x8001); // If the future state moved, this reference would become invalid, and // hilarity would ensue. let sentinel_ref: &Cell = &sentinel; // Test a few times that `sentinel` and `sentinel_ref` point to the same // data. assert_eq!(sentinel.get(), 0x8001); sentinel_ref.set(0x8002); assert_eq!(sentinel.get(), 0x8002); addrs.push(sentinel.as_ptr()); co.yield_(10).await; assert_eq!(sentinel.get(), 0x8002); sentinel_ref.set(0x8003); assert_eq!(sentinel.get(), 0x8003); addrs.push(sentinel.as_ptr()); co.yield_(20).await; assert_eq!(sentinel.get(), 0x8003); sentinel_ref.set(0x8004); assert_eq!(sentinel.get(), 0x8004); addrs.push(sentinel.as_ptr()); "done" } /// Create a generator, resume it once (so `sentinel_ref` gets /// initialized), and then move it out of the function. fn create_generator( addrs: &mut Vec<*const i32>, ) -> Gen + '_> { let mut gen = Gen::new(move |co| produce(addrs, co)); assert_eq!(gen.resume(), GeneratorState::Yielded(10)); gen } let mut addrs = Vec::new(); let mut gen = create_generator(&mut addrs); assert_eq!(gen.resume(), GeneratorState::Yielded(20)); assert_eq!(gen.resume(), GeneratorState::Complete("done")); drop(gen); assert!(addrs.iter().all(|&p| p == addrs[0])); } } genawaiter-0.99.1/src/sync/nightly_tests.rs000064400000000000000000000006071362137101300171370ustar0000000000000000// These tests can't be parsed on non-nightly compilers, so move them to a // separate file. use crate::{ops::GeneratorState, sync::Gen}; #[test] fn async_closure() { let mut gen = Gen::new(async move |co| { co.yield_(10).await; "done" }); assert_eq!(gen.resume(), GeneratorState::Yielded(10)); assert_eq!(gen.resume(), GeneratorState::Complete("done")); } genawaiter-0.99.1/src/sync/stream.rs000064400000000000000000000027451362205757600155570ustar0000000000000000use crate::{ops::GeneratorState, sync::Gen}; use futures_core::{ task::{Context, Poll}, Stream, }; use std::{future::Future, pin::Pin}; impl> Stream for Gen { type Item = Y; fn poll_next( mut self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll> { let fut = self.async_resume(); pin_mut!(fut); match fut.poll(cx) { Poll::Ready(GeneratorState::Yielded(x)) => Poll::Ready(Some(x)), Poll::Ready(GeneratorState::Complete(())) => Poll::Ready(None), Poll::Pending => Poll::Pending, } } } #[cfg(test)] mod tests { use crate::{ sync::{Co, Gen}, testing::SlowFuture, }; use futures::{executor::block_on_stream, stream}; #[test] fn blocking() { async fn produce(co: Co) { co.yield_(10).await; co.yield_(20).await; } let gen = Gen::new(produce); let stream = stream::iter(gen); let items: Vec<_> = block_on_stream(stream).collect(); assert_eq!(items, [10, 20]); } #[test] fn non_blocking() { async fn produce(co: Co) { SlowFuture::new().await; co.yield_(10).await; SlowFuture::new().await; co.yield_(20).await; } let gen = Gen::new(produce); let items: Vec<_> = block_on_stream(gen).collect(); assert_eq!(items, [10, 20]); } } genawaiter-0.99.1/src/testing.rs000064400000000000000000000015261362206672300147530ustar0000000000000000use std::{ future::Future, pin::Pin, task::{Context, Poll}, }; pub struct DummyFuture; impl Future for DummyFuture { type Output = (); fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { Poll::Pending } } /// A future that returns `Pending` a bunch of times before returning `Ready`. pub struct SlowFuture { countdown: i32, } impl SlowFuture { pub fn new() -> Self { Self { countdown: 10 } } } impl Future for SlowFuture { type Output = (); fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let this = unsafe { self.get_unchecked_mut() }; this.countdown -= 1; if this.countdown == 0 { Poll::Ready(()) } else { cx.waker().wake_by_ref(); Poll::Pending } } } genawaiter-0.99.1/src/waker.rs000064400000000000000000000010721356154023500144000ustar0000000000000000use std::{ ptr, task::{RawWaker, RawWakerVTable, Waker}, }; pub fn create() -> Waker { // Safety: The waker points to a vtable with functions that do nothing. Doing // nothing is memory-safe. unsafe { Waker::from_raw(RAW_WAKER) } } const RAW_WAKER: RawWaker = RawWaker::new(ptr::null(), &VTABLE); const VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop); unsafe fn clone(_: *const ()) -> RawWaker { RAW_WAKER } unsafe fn wake(_: *const ()) {} unsafe fn wake_by_ref(_: *const ()) {} unsafe fn drop(_: *const ()) {} genawaiter-0.99.1/.cargo_vcs_info.json0000644000000001121363130534200133520ustar00{ "git": { "sha1": "b7e93c2d444a5c63e94e14f6809c8dc27785c1c7" } }