Skip to content

Commit

Permalink
Auto merge of #96298 - petrochenkov:fromgen, r=estebank
Browse files Browse the repository at this point in the history
libcore: Add `iter::from_generator` which is like `iter::from_fn`, but for coroutines instead of functions

An equally useful little helper.

I didn't follow any of the async-wg work, so I don't know why something like this wasn't added before.
  • Loading branch information
bors committed May 27, 2022
2 parents b2c9872 + 5bf23f6 commit 4f68efa
Show file tree
Hide file tree
Showing 9 changed files with 67 additions and 34 deletions.
25 changes: 0 additions & 25 deletions compiler/rustc_data_structures/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@
#![feature(control_flow_enum)]
#![feature(core_intrinsics)]
#![feature(extend_one)]
#![feature(generator_trait)]
#![feature(generators)]
#![feature(let_else)]
#![feature(hash_raw_entry)]
#![feature(hasher_prefixfree_extras)]
Expand Down Expand Up @@ -114,9 +112,6 @@ pub mod unhash;
pub use ena::undo_log;
pub use ena::unify;

use std::ops::{Generator, GeneratorState};
use std::pin::Pin;

pub struct OnDrop<F: Fn()>(pub F);

impl<F: Fn()> OnDrop<F> {
Expand All @@ -135,26 +130,6 @@ impl<F: Fn()> Drop for OnDrop<F> {
}
}

struct IterFromGenerator<G>(G);

impl<G: Generator<Return = ()> + Unpin> Iterator for IterFromGenerator<G> {
type Item = G::Yield;

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

/// An adapter for turning a generator closure into an iterator, similar to `iter::from_fn`.
pub fn iter_from_generator<G: Generator<Return = ()> + Unpin>(
generator: G,
) -> impl Iterator<Item = G::Yield> {
IterFromGenerator(generator)
}

// See comments in src/librustc_middle/lib.rs
#[doc(hidden)]
pub fn __noop_fix_for_27438() {}
1 change: 1 addition & 0 deletions compiler/rustc_metadata/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#![feature(drain_filter)]
#![feature(generators)]
#![feature(generic_associated_types)]
#![feature(iter_from_generator)]
#![feature(let_chains)]
#![feature(let_else)]
#![feature(nll)]
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_metadata/src/rmeta/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use crate::rmeta::*;

use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
use rustc_data_structures::iter_from_generator;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::{join, par_iter, Lrc, ParallelIterator};
use rustc_hir as hir;
Expand Down Expand Up @@ -39,6 +38,7 @@ use rustc_span::{
use rustc_target::abi::VariantIdx;
use std::borrow::Borrow;
use std::hash::Hash;
use std::iter;
use std::num::NonZeroUsize;
use tracing::{debug, trace};

Expand Down Expand Up @@ -1134,7 +1134,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
// Encode this here because we don't do it in encode_def_ids.
record!(self.tables.expn_that_defined[def_id] <- tcx.expn_that_defined(local_def_id));
} else {
record_array!(self.tables.children[def_id] <- iter_from_generator(|| {
record_array!(self.tables.children[def_id] <- iter::from_generator(|| {
for item_id in md.item_ids {
match tcx.hir().item(*item_id).kind {
// Foreign items are planted into their parent modules
Expand Down
6 changes: 6 additions & 0 deletions library/core/src/iter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,12 @@ pub use self::traits::Iterator;
)]
pub use self::range::Step;

#[unstable(
feature = "iter_from_generator",
issue = "43122",
reason = "generators are unstable"
)]
pub use self::sources::from_generator;
#[stable(feature = "iter_empty", since = "1.2.0")]
pub use self::sources::{empty, Empty};
#[stable(feature = "iter_from_fn", since = "1.34.0")]
Expand Down
8 changes: 8 additions & 0 deletions library/core/src/iter/sources.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod empty;
mod from_fn;
mod from_generator;
mod once;
mod once_with;
mod repeat;
Expand All @@ -21,6 +22,13 @@ pub use self::repeat_with::{repeat_with, RepeatWith};
#[stable(feature = "iter_from_fn", since = "1.34.0")]
pub use self::from_fn::{from_fn, FromFn};

#[unstable(
feature = "iter_from_generator",
issue = "43122",
reason = "generators are unstable"
)]
pub use self::from_generator::from_generator;

#[stable(feature = "iter_successors", since = "1.34.0")]
pub use self::successors::{successors, Successors};

Expand Down
43 changes: 43 additions & 0 deletions library/core/src/iter/sources/from_generator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use crate::ops::{Generator, GeneratorState};
use crate::pin::Pin;

/// Creates a new iterator where each iteration calls the provided generator.
///
/// Similar to [`iter::from_fn`].
///
/// [`iter::from_fn`]: crate::iter::from_fn
///
/// # Examples
///
/// ```
/// #![feature(generators)]
/// #![feature(iter_from_generator)]
///
/// let it = std::iter::from_generator(|| {
/// yield 1;
/// yield 2;
/// yield 3;
/// });
/// let v: Vec<_> = it.collect();
/// assert_eq!(v, [1, 2, 3]);
/// ```
#[inline]
#[unstable(feature = "iter_from_generator", issue = "43122", reason = "generators are unstable")]
pub fn from_generator<G: Generator<Return = ()> + Unpin>(
generator: G,
) -> impl Iterator<Item = G::Yield> {
FromGenerator(generator)
}

struct FromGenerator<G>(G);

impl<G: Generator<Return = ()> + Unpin> Iterator for FromGenerator<G> {
type Item = G::Yield;

fn next(&mut self) -> Option<Self::Item> {
match Pin::new(&mut self.0).resume(()) {
GeneratorState::Yielded(n) => Some(n),
GeneratorState::Complete(()) => None,
}
}
}
4 changes: 2 additions & 2 deletions src/test/ui/async-await/issue-68112.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ LL | require_send(send_fut);
= help: the trait `Sync` is not implemented for `RefCell<i32>`
= note: required because of the requirements on the impl of `Send` for `Arc<RefCell<i32>>`
= note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:47:31: 47:36]`
= note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:47:31: 47:36]>`
= note: required because it appears within the type `std::future::from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:47:31: 47:36]>`
= note: required because it appears within the type `impl Future<Output = Arc<RefCell<i32>>>`
= note: required because it appears within the type `impl Future<Output = Arc<RefCell<i32>>>`
= note: required because it appears within the type `impl Future<Output = Arc<RefCell<i32>>>`
= note: required because it appears within the type `{ResumeTy, impl Future<Output = Arc<RefCell<i32>>>, (), i32, Ready<i32>}`
= note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:55:26: 59:6]`
= note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:55:26: 59:6]>`
= note: required because it appears within the type `std::future::from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:55:26: 59:6]>`
= note: required because it appears within the type `impl Future<Output = ()>`
note: required by a bound in `require_send`
--> $DIR/issue-68112.rs:11:25
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/async-await/partial-drop-partial-reinit.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ LL | async fn foo() {
= note: required because it appears within the type `(NotSend,)`
= note: required because it appears within the type `{ResumeTy, (NotSend,), impl Future<Output = ()>, ()}`
= note: required because it appears within the type `[static generator@$DIR/partial-drop-partial-reinit.rs:22:16: 27:2]`
= note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/partial-drop-partial-reinit.rs:22:16: 27:2]>`
= note: required because it appears within the type `std::future::from_generator::GenFuture<[static generator@$DIR/partial-drop-partial-reinit.rs:22:16: 27:2]>`
= note: required because it appears within the type `impl Future<Output = ()>`
= note: required because it appears within the type `impl Future<Output = ()>`
note: required by a bound in `gimme_send`
Expand Down
8 changes: 4 additions & 4 deletions src/test/ui/chalkify/bugs/async.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ LL | | x
LL | | }
| |_^ the trait `Generator<ResumeTy>` is not implemented for `[static generator@$DIR/async.rs:7:29: 9:2]`
|
note: required by a bound in `from_generator`
note: required by a bound in `std::future::from_generator`
--> $SRC_DIR/core/src/future/mod.rs:LL:COL
|
LL | T: Generator<ResumeTy, Yield = ()>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `from_generator`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `std::future::from_generator`

error[E0280]: the requirement `<[static generator@$DIR/async.rs:7:29: 9:2] as Generator<ResumeTy>>::Yield == ()` is not satisfied
--> $DIR/async.rs:7:29
Expand All @@ -22,11 +22,11 @@ LL | | x
LL | | }
| |_^
|
note: required by a bound in `from_generator`
note: required by a bound in `std::future::from_generator`
--> $SRC_DIR/core/src/future/mod.rs:LL:COL
|
LL | T: Generator<ResumeTy, Yield = ()>,
| ^^^^^^^^^^ required by this bound in `from_generator`
| ^^^^^^^^^^ required by this bound in `std::future::from_generator`

error[E0280]: the requirement `<impl Future<Output = u32> as Future>::Output == u32` is not satisfied
--> $DIR/async.rs:7:29
Expand Down

0 comments on commit 4f68efa

Please sign in to comment.