-
-
Notifications
You must be signed in to change notification settings - Fork 14.2k
Add core::stream::from_iter
#81797
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 core::stream::from_iter
#81797
Conversation
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I recommend seeing how the same function is implemented in futures. (that is the most widely used in the ecosystem.)
As for prior art, the same functions in futures, tokio, and futures-lite are called iter.
EDIT: This PR's implementation seems to be based on async-std and I opened an issue in async-std repo about it: async-rs/async-std#953
|
failing build |
|
@yoshuawuyts Ping from triage! CI is still red here. Would you mind fixing that? Thanks! |
|
Hey! Yeah I'm on vacation right now. I'll make sure to get around to this either next week or the week after! I have a few outstanding PRs — just need to find a day to update them all 😅 |
|
@yoshuawuyts Ping from triage! Any updates? |
|
@yoshuawuyts Are you back from vacation? |
|
@JohnCSimon heya, I've been busy with a move among other things. I'll be back to work starting July 15th! edit: found some free time today, and repaired my local setup. I've updated the PR with all feedback provided, and it should be good again for review! |
This comment has been minimized.
This comment has been minimized.
|
@bors r+ |
|
📌 Commit 660f585 has been approved by |
|
⌛ Testing commit 660f585 with merge b75dbad85bade79beb9f5c73b11dd9c463958c7f... |
|
💔 Test failed - checks-actions |
|
@bors retry |
…lnay Add `core::stream::from_iter` _Tracking issue: https://github.com/rust-lang/rust/issues/81798_ This_ PR implements `std::stream::from_iter`, as outlined in the _"Converting an Iterator to a Stream"_ section of the [Stream RFC](https://github.com/nellshamrell/rfcs/blob/add-async-stream-rfc/text/0000-async-stream.md#converting-an-iterator-to-a-stream). This function enables converting an `Iterator` to a `Stream` by wrapping each item in the iterator with a `Poll::Ready` instance. r? `@tmandry` cc/ `@rust-lang/libs` `@rust-lang/wg-async-foundations` ## Example Being able to convert from an iterator into a stream is useful when refactoring from iterative loops into a more functional adapter-based style. This is fairly common when using more complex `filter` / `map` / `find` chains. In its basic form this conversion looks like this: **before** ```rust let mut output = vec![]; for item in my_vec { let out = do_io(item).await?; output.push(out); } ``` **after** ```rust use std::stream; let output = stream::from_iter(my_vec.iter()) .map(async |item| do_io(item).await) .collect()?; ``` Having a way to convert an `Iterator` to a `Stream` is essential in enabling this flow. ## Implementation Notes This PR makes use of `unsafe {}` to pin an item. Currently we're having conversations on the libs stream in Zulip how to bring `pin-project` in as a dependency to `core` so we can omit the `unsafe {}`. This PR also includes a documentation block which references `Stream::next` which currently doesn't exist in the stdlib (originally included in the RFC and PR, but later omitted because of an unresolved issue). `stream::from_iter` can't stabilize before `Stream` does, and there's still a chance we may stabilize `Stream` with a `next` method. So this PR includes documentation referencing that method, which we can remove as part of stabilization if by any chance we don't have `Stream::next`. ## Alternatives Considered ### `impl IntoStream for T: IntoIterator` An obvious question would be whether we could make it so every iterator can automatically be converted into a stream by calling `into_stream` on it. The answer is: "perhaps, but it could cause type issues". Types like `std::collections` may want to opt to create manual implementations for `IntoStream` and `IntoIter`, which wouldn't be possible if it was implemented through a catch-all trait. Possibly an alternative such as `impl IntoStream for T: Iterator` could work, but it feels somewhat restrictive. In the end, converting an iterator to a stream is likely to be a bit of a niche case. And even then, **adding a standalone function to convert an `Iterator` into a `Stream` would not be mutually exclusive with a blanket implementation**. ### Naming The exact name can be debated in the period before stabilization. But I've chosen `stream::from_iter` rather than `stream::iter` because we are _creating a stream from an iterator_ rather than _iterating a stream_. We also expect to add a stream counterpart to `iter::from_fn` later on (blocked on async closures), and having `stream::from_fn` and `stream::from_iter` would feel like a consistent pair. It also has prior art in `async_std::stream::from_iter`. ## Future Directions ### Stream conversions for collections This is a building block towards implementing `stream/stream_mut/into_stream` methods for `std::collections`, `std::vec`, and more. This would allow even quicker refactorings from using loops to using iterator adapters by omitting the import altogether: **before** ```rust use std::stream; let output = stream::from_iter(my_vec.iter()) .map(async |item| do_io(item).await) .collect()?; ``` **after** ```rust let output = my_vec .stream() .map(async |item| do_io(item).await) .collect()?; ```
|
⌛ Testing commit 660f585 with merge 669248f5fc704c5d7e527bc889c1f49937a6d5f3... |
|
@bors retry rolled-up |
Rollup of 8 pull requests Successful merges: - rust-lang#81797 (Add `core::stream::from_iter`) - rust-lang#87267 (Remove space after negative sign in Literal to_string) - rust-lang#87663 (Rustdoc accessibility: use an icon for the [-]/[+] controls) - rust-lang#87720 (don't use .into() to convert types to identical types (clippy::useless_conversion)) - rust-lang#87723 (Use .contains instead of manual reimplementation.) - rust-lang#87729 (Remove the aarch64 `crypto` target_feature) - rust-lang#87731 (Update cargo) - rust-lang#87734 (Test dropping union fields more) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
|
☔ The latest upstream changes (presumably #87746) made this pull request unmergeable. Please resolve the merge conflicts. |
Tracking issue: #81798
This_ PR implements
std::stream::from_iter, as outlined in the "Converting an Iterator to a Stream" section of the Stream RFC. This function enables converting anIteratorto aStreamby wrapping each item in the iterator with aPoll::Readyinstance.r? @tmandry
cc/ @rust-lang/libs @rust-lang/wg-async-foundations
Example
Being able to convert from an iterator into a stream is useful when refactoring from iterative loops into a more functional adapter-based style. This is fairly common when using more complex
filter/map/findchains. In its basic form this conversion looks like this:before
after
Having a way to convert an
Iteratorto aStreamis essential in enabling this flow.Implementation Notes
This PR makes use of
unsafe {}to pin an item. Currently we're having conversations on the libs stream in Zulip how to bringpin-projectin as a dependency tocoreso we can omit theunsafe {}.This PR also includes a documentation block which references
Stream::nextwhich currently doesn't exist in the stdlib (originally included in the RFC and PR, but later omitted because of an unresolved issue).stream::from_itercan't stabilize beforeStreamdoes, and there's still a chance we may stabilizeStreamwith anextmethod. So this PR includes documentation referencing that method, which we can remove as part of stabilization if by any chance we don't haveStream::next.Alternatives Considered
impl IntoStream for T: IntoIteratorAn obvious question would be whether we could make it so every iterator can automatically be converted into a stream by calling
into_streamon it. The answer is: "perhaps, but it could cause type issues". Types likestd::collectionsmay want to opt to create manual implementations forIntoStreamandIntoIter, which wouldn't be possible if it was implemented through a catch-all trait.Possibly an alternative such as
impl IntoStream for T: Iteratorcould work, but it feels somewhat restrictive. In the end, converting an iterator to a stream is likely to be a bit of a niche case. And even then, adding a standalone function to convert anIteratorinto aStreamwould not be mutually exclusive with a blanket implementation.Naming
The exact name can be debated in the period before stabilization. But I've chosen
stream::from_iterrather thanstream::iterbecause we are creating a stream from an iterator rather than iterating a stream. We also expect to add a stream counterpart toiter::from_fnlater on (blocked on async closures), and havingstream::from_fnandstream::from_iterwould feel like a consistent pair. It also has prior art inasync_std::stream::from_iter.Future Directions
Stream conversions for collections
This is a building block towards implementing
stream/stream_mut/into_streammethods forstd::collections,std::vec, and more. This would allow even quicker refactorings from using loops to using iterator adapters by omitting the import altogether:before
after