Skip to content

Commit

Permalink
follow [rename Generator to Coroutine](rust-lang/rust#116958) and fix t…
Browse files Browse the repository at this point in the history
  • Loading branch information
viruscamp committed Aug 27, 2024
1 parent b6fd587 commit ecbdae4
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 63 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# version 0.4.0
* follow [rename Generator to Coroutine](https://github.com/rust-lang/rust/pull/116958) and fix #10

# version 0.3
* made the crate no_std compatible (#5)
* added struct GenIterReturn and macro gen_iter_return! to iterate over a generator and get the return value (#6)
Expand Down
7 changes: 4 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
[package]
name = "gen-iter"
version = "0.2.1"
version = "0.4.0"
edition = "2021"
authors = ["tinaun <tinagma@gmail.com>"]
keywords = ["generator", "iterator"]
description = "temporary util for creating iterators using generators"
keywords = ["coroutine", "generator", "iterator"]
description = "temporary util for creating iterators using coroutines"

documentation = "https://docs.rs/gen-iter"
repository = "https://github.com/tinaun/gen-iter"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# gen_iter - iterators using generators.
# gen_iter - iterators using coroutines/generators.

see [the docs](https://docs.rs/gen-iter) for examples and usage.

Expand Down
33 changes: 18 additions & 15 deletions src/gen_iter.rs
Original file line number Diff line number Diff line change
@@ -1,33 +1,33 @@
use core::ops::{Generator, GeneratorState};
use core::iter::Iterator;
use core::marker::Unpin;
use core::ops::{Coroutine, CoroutineState};
use core::pin::Pin;

/// an iterator that holds an internal generator representing
/// an iterator that holds an internal coroutine representing
/// the iteration state
#[derive(Copy, Clone, Debug)]
pub struct GenIter<T>(pub T)
where
T: Generator<Return = ()> + Unpin;
T: Coroutine<Return = ()> + Unpin;

impl<T> Iterator for GenIter<T>
where
T: Generator<Return = ()> + Unpin,
T: Coroutine<Return = ()> + Unpin,
{
type Item = T::Yield;

#[inline]
fn next(&mut self) -> Option<Self::Item> {
match Pin::new(&mut self.0).resume(()) {
GeneratorState::Yielded(n) => Some(n),
GeneratorState::Complete(()) => None,
CoroutineState::Yielded(n) => Some(n),
CoroutineState::Complete(()) => None,
}
}
}

impl<G> From<G> for GenIter<G>
where
G: Generator<Return = ()> + Unpin,
G: Coroutine<Return = ()> + Unpin,
{
#[inline]
fn from(gen: G) -> Self {
Expand All @@ -36,10 +36,10 @@ where
}


/// macro to simplify iterator - via - generator construction
/// macro to simplify iterator - via - coroutine construction
///
/// ```
/// #![feature(generators)]
/// #![feature(coroutines)]
///
/// use gen_iter::gen_iter;
///
Expand All @@ -56,10 +56,10 @@ where
#[macro_export]
macro_rules! gen_iter {
($block: block) => {
$crate::GenIter(|| $block)
$crate::GenIter(#[coroutine] || $block)
};
(move $block: block) => {
$crate::GenIter(move || $block)
$crate::GenIter(#[coroutine] move || $block)
}
}

Expand All @@ -82,10 +82,13 @@ mod tests {

#[test]
fn into_gen_iter() {
let mut g: GenIter<_> = (|| {
yield 1;
yield 2;
}).into();
let mut g: GenIter<_> = (
#[coroutine]
|| {
yield 1;
yield 2;
}
).into();

assert_eq!(g.next(), Some(1));
assert_eq!(g.next(), Some(2));
Expand Down
72 changes: 39 additions & 33 deletions src/gen_iter_return.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
use core::ops::{Generator, GeneratorState};
use core::iter::{Iterator, FusedIterator};
use core::iter::{FusedIterator, Iterator};
use core::marker::Unpin;
use core::ops::{Coroutine, CoroutineState};
use core::pin::Pin;

/// `GenIterReturn<G>` holds a generator `G` or the return value of `G`,
/// `GenIterReturn<G>` holds a coroutine `G` or the return value of `G`,
/// `&mut GenIterReturn<G>` acts as an iterator.
///
///
/// Differences with `GenIter<G>`:
/// 1. able to get return value of a generator
/// 2. safe to call `next()` after generator is done without panic
/// 1. able to get return value of a coroutine
/// 2. safe to call `next()` after coroutine is done without panic
/// 3. maybe less efficient than `GenIter<G>`
#[derive(Copy, Clone, Debug)]
pub struct GenIterReturn<G: Generator + Unpin>(Result<G::Return, G>);
pub struct GenIterReturn<G: Coroutine + Unpin>(Result<G::Return, G>);

impl<G: Generator + Unpin> GenIterReturn<G> {
impl<G: Coroutine + Unpin> GenIterReturn<G> {
#[inline]
pub fn new(g: G) -> Self {
GenIterReturn(Err(g))
Expand All @@ -37,43 +37,43 @@ impl<G: Generator + Unpin> GenIterReturn<G> {
/// in which return value cannot be got.
/// ```compile_fail
/// // !!INVALID CODE!!
/// # #![feature(generators)]
/// # #![feature(coroutines)]
/// # use gen_iter::gen_iter_return;
/// let mut g = gen_iter_return!({ yield 1; return "done"; });
/// for v in g {} // invalid, because `GenIterReturn<G>` is not `Iterator`
/// let ret = g.return_or_self(); // g is dropped after for loop
/// ```
impl<G: Generator + Unpin> Iterator for &mut GenIterReturn<G> {
impl<G: Coroutine + Unpin> Iterator for &mut GenIterReturn<G> {
type Item = G::Yield;

#[inline]
fn next(&mut self) -> Option<Self::Item> {
match self.0 {
Ok(_) => None,
Err(ref mut g) => match Pin::new(g).resume(()) {
GeneratorState::Yielded(y) => Some(y),
GeneratorState::Complete(r) => {
CoroutineState::Yielded(y) => Some(y),
CoroutineState::Complete(r) => {
self.0 = Ok(r);
None
},
}
},
}
}
}

/// `GenIterReturn<G>` satisfies the trait `FusedIterator`
impl<G: Generator + Unpin> FusedIterator for &mut GenIterReturn<G> {}
impl<G: Coroutine + Unpin> FusedIterator for &mut GenIterReturn<G> {}

impl<G: Generator + Unpin> From<G> for GenIterReturn<G> {
impl<G: Coroutine + Unpin> From<G> for GenIterReturn<G> {
#[inline]
fn from(g: G) -> Self {
GenIterReturn::new(g)
}
}

/// macro to simplify iterator - via - generator with return value construction
/// macro to simplify iterator - via - coroutine with return value construction
/// ```
/// #![feature(generators)]
/// #![feature(coroutines)]
///
/// use gen_iter::gen_iter_return;
///
Expand All @@ -84,18 +84,18 @@ impl<G: Generator + Unpin> From<G> for GenIterReturn<G> {
/// });
///
/// assert_eq!((&mut g).collect::<Vec<_>>(), [1, 2]); // use `&mut g` as an iterator
/// assert_eq!(g.is_done(), true); // check whether generator is done
/// assert_eq!(g.is_done(), true); // check whether the coroutine is done
/// assert_eq!((&mut g).next(), None); // safe to call `next()` after done
/// assert_eq!(g.return_or_self().ok(), Some("done")); // get return value of generator
/// assert_eq!(g.return_or_self().ok(), Some("done")); // get return value of the coroutine
/// ```
#[macro_export]
macro_rules! gen_iter_return {
($block: block) => {
$crate::GenIterReturn::new(|| $block)
$crate::GenIterReturn::new(#[coroutine] || $block)
};
(move $block: block) => {
$crate::GenIterReturn::new(move || $block)
}
$crate::GenIterReturn::new(#[coroutine] move || $block)
};
}

#[cfg(test)]
Expand All @@ -106,17 +106,20 @@ mod tests {
/// and show that it won't panic when call `next()` even exhausted.
#[test]
fn it_works() {
let mut g = GenIterReturn::new(|| {
yield 1;
return "done";
});
let mut g = GenIterReturn::new(
#[coroutine]
|| {
yield 1;
return "done";
},
);

assert_eq!((&mut g).next(), Some(1));
assert_eq!(g.is_done(), false);

g = match g.return_or_self() {
Ok(_) => panic!("generator is done but should not"),
Err(g) => g
Ok(_) => panic!("coroutine is done but should not"),
Err(g) => g,
};

assert_eq!((&mut g).next(), None);
Expand All @@ -128,11 +131,14 @@ mod tests {
}

#[test]
fn from_generator() {
let mut g = GenIterReturn::from(|| {
yield 1;
return "done";
});
fn from_coroutine() {
let mut g = GenIterReturn::from(
#[coroutine]
|| {
yield 1;
return "done";
},
);

assert_eq!((&mut g).next(), Some(1));
assert_eq!((&mut g).next(), None);
Expand Down
28 changes: 17 additions & 11 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
//! # gen_iter - create generators to use as iterators
//! # gen_iter - create coroutines to use as iterators
//!
//! **Important: [rename Generator to Coroutine](https://github.com/rust-lang/rust/pull/116958)**
//!
//! ## [`GenIter`] and [`gen_iter!`]
//! [`GenIter`] converts a [`Generator<(), Return=()>`](core::ops::Generator) into an iterator over the
//! yielded type of the generator. The return type of the generator needs to be `()`.
//! ## Prerequirements
//! Nightly rust toolchain of edition 2021 after 2023-10-21.
//!
//! ## [`GenIter`] and [`gen_iter!`]
//! [`GenIter`] converts a [`Coroutine<(), Return=()>`](core::ops::Coroutine) into an iterator over the
//! yielded type of the coroutine. The return type of the coroutine needs to be `()`.
//!
//! [`gen_iter!`] helps to create a [`GenIter`]
//!
//! ```
//! #![feature(generators)]
//! #![feature(coroutines)]
//!
//! use gen_iter::gen_iter;
//!
Expand All @@ -32,14 +37,14 @@
//! ```
//!
//! ## [`GenIterReturn`] and [`gen_iter_return!`]
//! [`GenIterReturn`] can be converted from a [`Generator<()>`](core::ops::Generator),
//! [`GenIterReturn`] can be converted from a [`Coroutine<()>`](core::ops::Coroutine),
//! `&mut GenIterReturn<G>` can be used as iterator.
//! The return value of the generator can be got after the iterator is exhausted.
//! The return value of the coroutine can be got after the iterator is exhausted.
//!
//! [`gen_iter_return!`] helps to create a [`GenIterReturn`].
//!
//! ```
//! #![feature(generators)]
//! #![feature(coroutines)]
//!
//! use gen_iter::gen_iter_return;
//!
Expand All @@ -52,12 +57,13 @@
//! for y in &mut g {
//! println!("yield {}", y);
//! }
//! println!("generator is_done={}", g.is_done()); // true
//! println!("generator returns {}", g.return_or_self().ok().unwrap()); // "done"
//! println!("coroutine is_done={}", g.is_done()); // true
//! println!("coroutine returns {}", g.return_or_self().ok().unwrap()); // "done"
//! ```

#![no_std]
#![feature(generators, generator_trait)]
#![feature(coroutines, coroutine_trait)]
#![feature(stmt_expr_attributes)]

mod gen_iter;
pub use gen_iter::*;
Expand Down

0 comments on commit ecbdae4

Please sign in to comment.