Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add no_std compatibility and remove Coroutine trait #36

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,12 @@ rustversion = "1.0.2"
trybuild = "1"

[features]
default = ["proc_macro"]
alloc = []
default = ["proc_macro", "rc", "sync"]
futures03 = ["futures-core"]
nightly = []
strict = []
proc_macro = ["genawaiter-proc-macro", "proc-macro-hack", "genawaiter-macro/proc_macro"]
rc = []
std = []
strict = []
sync = []
3 changes: 0 additions & 3 deletions genawaiter-proc-macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,11 @@
#![warn(clippy::cargo, clippy::pedantic)]
#![cfg_attr(feature = "strict", deny(warnings))]

extern crate proc_macro;

use crate::visit::YieldReplace;
use proc_macro::TokenStream;
use proc_macro_error::{abort, abort_call_site, proc_macro_error};
use proc_macro_hack::proc_macro_hack;
use quote::quote;
use std::string::ToString;
use syn::{
self,
parse_macro_input,
Expand Down
2 changes: 1 addition & 1 deletion src/core.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{ops::GeneratorState, waker};
use std::{
use core::{
future::Future,
pin::Pin,
task::{Context, Poll},
Expand Down
2 changes: 1 addition & 1 deletion src/ext.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![allow(clippy::module_name_repetitions)]

use std::mem;
use core::mem;

pub trait MaybeUninitExt<T> {
unsafe fn assume_init_get_mut(&mut self) -> &mut T;
Expand Down
31 changes: 14 additions & 17 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,7 @@ Values can be yielded from the generator by calling `yield_`, and immediately aw
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`.
- Call `resume()`. The values will be returned in a `GeneratorState::Yielded`.

```rust
# #[cfg(feature = "proc_macro")]
Expand All @@ -129,7 +128,7 @@ ways:
let mut generator = gen!({
yield_!(10);
});
let ten = generator.resume();
let ten = generator.resume(());
assert_eq!(ten, GeneratorState::Yielded(10));
# }
```
Expand All @@ -152,7 +151,7 @@ ways:

## Resume

You can also send values back into the generator, by using `resume_with`. The generator
You can also send values back into the generator, by using `resume`. The generator
receives them from the future returned by `yield_`.

```rust
Expand All @@ -166,8 +165,8 @@ let mut printer = gen!({
println!("{}", string);
}
});
printer.resume_with("hello");
printer.resume_with("world");
printer.resume("hello");
printer.resume("world");
# }
```

Expand All @@ -185,8 +184,8 @@ let mut generator = gen!({
yield_!(10);
"done"
});
assert_eq!(generator.resume(), GeneratorState::Yielded(10));
assert_eq!(generator.resume(), GeneratorState::Complete("done"));
assert_eq!(generator.resume(()), GeneratorState::Yielded(10));
assert_eq!(generator.resume(()), GeneratorState::Complete("done"));
# }
```

Expand Down Expand Up @@ -230,13 +229,13 @@ works even without the `futures03` feature.)
# #[cfg(feature = "proc_macro")]
# async fn feature_gate() {
# use genawaiter::{sync::gen, yield_, GeneratorState};
# use std::task::Poll;
# use core::task::Poll;
#
# let mut gen = gen!({
# yield_!(10);
# });
#
match gen.async_resume().await {
match gen.async_resume(()).await {
GeneratorState::Yielded(_) => {}
GeneratorState::Complete(_) => {}
}
Expand All @@ -250,10 +249,6 @@ This crate supplies [`Generator`](trait.Generator.html) and
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))]
Expand All @@ -264,7 +259,7 @@ resume argument type to `()`, but in a `Coroutine` it can be anything.
#[cfg(test)]
extern crate self as genawaiter;

pub use crate::ops::{Coroutine, Generator, GeneratorState};
pub use crate::ops::{Generator, GeneratorState};

#[cfg(feature = "proc_macro")]
use proc_macro_hack::proc_macro_hack;
Expand All @@ -287,7 +282,7 @@ use proc_macro_hack::proc_macro_hack;
/// });
///
/// let mut my_generator = Gen::new(my_producer);
/// # my_generator.resume();
/// # my_generator.resume(());
/// ```
#[cfg(feature = "proc_macro")]
#[proc_macro_hack]
Expand All @@ -311,7 +306,7 @@ pub use genawaiter_proc_macro::sync_producer;
/// });
///
/// let mut my_generator = Gen::new(my_producer);
/// # my_generator.resume();
/// # my_generator.resume(());
/// ```
#[cfg(feature = "proc_macro")]
#[proc_macro_hack]
Expand All @@ -327,8 +322,10 @@ mod ext;
#[macro_use]
mod macros;
mod ops;
#[cfg(feature = "rc")]
pub mod rc;
pub mod stack;
#[cfg(feature = "sync")]
pub mod sync;
#[cfg(test)]
mod testing;
Expand Down
2 changes: 1 addition & 1 deletion src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,6 @@ macro_rules! pin_mut {
($x:ident) => {
let mut $x = $x;
#[allow(unused_mut)]
let mut $x = unsafe { ::std::pin::Pin::new_unchecked(&mut $x) };
let mut $x = unsafe { ::core::pin::Pin::new_unchecked(&mut $x) };
};
}
56 changes: 18 additions & 38 deletions src/ops.rs
Original file line number Diff line number Diff line change
@@ -1,62 +1,42 @@
use 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<Self::Yield, Self::Return>;
}
use core::pin::Pin;

/// A trait implemented for generator types.
///
/// This is modeled after the stdlib's nightly-only [`std::ops::Generator`].
pub trait Generator {
/// This is modeled after the stdlib's nightly-only [`core::ops::Generator`].
pub trait Generator<R = ()> {
/// 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<Self::Yield, Self::Return>;
}

impl<C: Coroutine<Resume = ()>> Generator for C {
type Yield = <Self as Coroutine>::Yield;
type Return = <Self as Coroutine>::Return;

#[must_use]
fn resume(self: Pin<&mut Self>) -> GeneratorState<Self::Yield, Self::Return> {
self.resume_with(())
}
fn resume(self: Pin<&mut Self>, arg: R) -> GeneratorState<Self::Yield, Self::Return>;
}

/// The result of a generator resumption.
///
/// This is modeled after the stdlib's nightly-only
/// [`std::ops::GeneratorState`].
/// [`core::ops::GeneratorState`].
///
/// This enum is returned from the [`Generator::resume`] method and indicates
/// the possible return values of a generator. Currently this corresponds to
/// either a suspension point (Yielded) or a termination point (Complete).
#[derive(PartialEq, Debug)]
#[allow(clippy::module_name_repetitions)]
pub enum GeneratorState<Y, R> {
/// The generator suspended with a value.
///
/// This state indicates that a generator has been suspended, and typically
/// corresponds to a yield statement. The value provided in this variant
/// corresponds to the expression passed to yield and allows generators to
/// provide a value each time they yield.
Yielded(Y),

/// The generator completed with a return value.
///
/// This state indicates that a generator has finished execution with the
/// provided value. Once a generator has returned Complete it is considered
/// a programmer error to call resume again.
Complete(R),
}
5 changes: 4 additions & 1 deletion src/rc/engine.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
extern crate alloc;

use crate::{core, core::Next};
use std::{cell::Cell, rc::Rc};
use ::core::cell::Cell;
use alloc::rc::Rc;

pub struct Airlock<Y, R>(Rc<Cell<Next<Y, R>>>);

Expand Down
28 changes: 9 additions & 19 deletions src/rc/generator.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::{
core::{advance, async_advance, Airlock as _, Next},
ops::{Coroutine, GeneratorState},
ops::{Generator, GeneratorState},
rc::{engine::Airlock, Co},
};
use std::{future::Future, pin::Pin};
use core::{future::Future, pin::Pin};

/// This is a generator which stores its state on the heap.
///
Expand Down Expand Up @@ -42,23 +42,13 @@ impl<Y, R, F: Future> Gen<Y, R, F> {
/// `Completed` is returned.
///
/// [_See the module-level docs for examples._](.)
pub fn resume_with(&mut self, arg: R) -> GeneratorState<Y, F::Output> {
pub fn resume(&mut self, arg: R) -> GeneratorState<Y, F::Output> {
self.airlock.replace(Next::Resume(arg));
advance(self.future.as_mut(), &self.airlock)
}
}

impl<Y, F: Future> Gen<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<Y, F::Output> {
self.resume_with(())
}

impl<Y, R, F: Future> Gen<Y, R, F> {
/// Resumes execution of the generator.
///
/// If the generator pauses without yielding, `Poll::Pending` is returned.
Expand All @@ -68,21 +58,21 @@ impl<Y, F: Future> Gen<Y, (), F> {
/// [_See the module-level docs for examples._](.)
pub fn async_resume(
&mut self,
arg: R,
) -> impl Future<Output = GeneratorState<Y, F::Output>> + '_ {
self.airlock.replace(Next::Resume(()));
self.airlock.replace(Next::Resume(arg));
async_advance(self.future.as_mut(), self.airlock.clone())
}
}

impl<Y, R, F: Future> Coroutine for Gen<Y, R, F> {
impl<Y, R, F: Future> Generator<R> for Gen<Y, R, F> {
type Yield = Y;
type Resume = R;
type Return = F::Output;

fn resume_with(
fn resume(
mut self: Pin<&mut Self>,
arg: R,
) -> GeneratorState<Self::Yield, Self::Return> {
Self::resume_with(&mut *self, arg)
Self::resume(&mut *self, arg)
}
}
6 changes: 3 additions & 3 deletions src/rc/iterator.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{ops::GeneratorState, rc::Gen};
use std::future::Future;
use core::future::Future;

impl<Y, F: Future<Output = ()>> IntoIterator for Gen<Y, (), F> {
type Item = Y;
Expand All @@ -19,7 +19,7 @@ impl<Y, F: Future<Output = ()>> Iterator for IntoIter<Y, F> {
type Item = Y;

fn next(&mut self) -> Option<Self::Item> {
match self.generator.resume() {
match self.generator.resume(()) {
GeneratorState::Yielded(x) => Some(x),
GeneratorState::Complete(()) => None,
}
Expand All @@ -29,7 +29,7 @@ impl<Y, F: Future<Output = ()>> Iterator for IntoIter<Y, F> {
#[cfg(test)]
mod tests {
use crate::rc::{Co, Gen};
use std::iter::IntoIterator;
use core::iter::IntoIterator;

async fn produce(mut co: Co<i32>) {
co.yield_(10).await;
Expand Down
Loading