diff options
Diffstat (limited to 'library/core/src/async_iter')
-rw-r--r-- | library/core/src/async_iter/async_iter.rs | 111 | ||||
-rw-r--r-- | library/core/src/async_iter/from_iter.rs | 38 | ||||
-rw-r--r-- | library/core/src/async_iter/mod.rs | 128 |
3 files changed, 277 insertions, 0 deletions
diff --git a/library/core/src/async_iter/async_iter.rs b/library/core/src/async_iter/async_iter.rs new file mode 100644 index 000000000..016a3685e --- /dev/null +++ b/library/core/src/async_iter/async_iter.rs @@ -0,0 +1,111 @@ +use crate::ops::DerefMut; +use crate::pin::Pin; +use crate::task::{Context, Poll}; + +/// An interface for dealing with asynchronous iterators. +/// +/// This is the main async iterator trait. For more about the concept of async iterators +/// generally, please see the [module-level documentation]. In particular, you +/// may want to know how to [implement `AsyncIterator`][impl]. +/// +/// [module-level documentation]: index.html +/// [impl]: index.html#implementing-async-iterator +#[unstable(feature = "async_iterator", issue = "79024")] +#[must_use = "async iterators do nothing unless polled"] +#[doc(alias = "Stream")] +pub trait AsyncIterator { + /// The type of items yielded by the async iterator. + type Item; + + /// Attempt to pull out the next value of this async iterator, registering the + /// current task for wakeup if the value is not yet available, and returning + /// `None` if the async iterator is exhausted. + /// + /// # Return value + /// + /// There are several possible return values, each indicating a distinct + /// async iterator state: + /// + /// - `Poll::Pending` means that this async iterator's next value is not ready + /// yet. Implementations will ensure that the current task will be notified + /// when the next value may be ready. + /// + /// - `Poll::Ready(Some(val))` means that the async iterator has successfully + /// produced a value, `val`, and may produce further values on subsequent + /// `poll_next` calls. + /// + /// - `Poll::Ready(None)` means that the async iterator has terminated, and + /// `poll_next` should not be invoked again. + /// + /// # Panics + /// + /// Once an async iterator has finished (returned `Ready(None)` from `poll_next`), calling its + /// `poll_next` method again may panic, block forever, or cause other kinds of + /// problems; the `AsyncIterator` trait places no requirements on the effects of + /// such a call. However, as the `poll_next` method is not marked `unsafe`, + /// Rust's usual rules apply: calls must never cause undefined behavior + /// (memory corruption, incorrect use of `unsafe` functions, or the like), + /// regardless of the async iterator's state. + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>; + + /// Returns the bounds on the remaining length of the async iterator. + /// + /// Specifically, `size_hint()` returns a tuple where the first element + /// is the lower bound, and the second element is the upper bound. + /// + /// The second half of the tuple that is returned is an <code>[Option]<[usize]></code>. + /// A [`None`] here means that either there is no known upper bound, or the + /// upper bound is larger than [`usize`]. + /// + /// # Implementation notes + /// + /// It is not enforced that an async iterator implementation yields the declared + /// number of elements. A buggy async iterator may yield less than the lower bound + /// or more than the upper bound of elements. + /// + /// `size_hint()` is primarily intended to be used for optimizations such as + /// reserving space for the elements of the async iterator, but must not be + /// trusted to e.g., omit bounds checks in unsafe code. An incorrect + /// implementation of `size_hint()` should not lead to memory safety + /// violations. + /// + /// That said, the implementation should provide a correct estimation, + /// because otherwise it would be a violation of the trait's protocol. + /// + /// The default implementation returns <code>(0, [None])</code> which is correct for any + /// async iterator. + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + (0, None) + } +} + +#[unstable(feature = "async_iterator", issue = "79024")] +impl<S: ?Sized + AsyncIterator + Unpin> AsyncIterator for &mut S { + type Item = S::Item; + + fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { + S::poll_next(Pin::new(&mut **self), cx) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + (**self).size_hint() + } +} + +#[unstable(feature = "async_iterator", issue = "79024")] +impl<P> AsyncIterator for Pin<P> +where + P: DerefMut, + P::Target: AsyncIterator, +{ + type Item = <P::Target as AsyncIterator>::Item; + + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { + <P::Target as AsyncIterator>::poll_next(self.as_deref_mut(), cx) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + (**self).size_hint() + } +} diff --git a/library/core/src/async_iter/from_iter.rs b/library/core/src/async_iter/from_iter.rs new file mode 100644 index 000000000..3180187af --- /dev/null +++ b/library/core/src/async_iter/from_iter.rs @@ -0,0 +1,38 @@ +use crate::pin::Pin; + +use crate::async_iter::AsyncIterator; +use crate::task::{Context, Poll}; + +/// An async iterator that was created from iterator. +/// +/// This async iterator is created by the [`from_iter`] function. +/// See it documentation for more. +/// +/// [`from_iter`]: fn.from_iter.html +#[unstable(feature = "async_iter_from_iter", issue = "81798")] +#[derive(Clone, Debug)] +pub struct FromIter<I> { + iter: I, +} + +#[unstable(feature = "async_iter_from_iter", issue = "81798")] +impl<I> Unpin for FromIter<I> {} + +/// Converts an iterator into an async iterator. +#[unstable(feature = "async_iter_from_iter", issue = "81798")] +pub fn from_iter<I: IntoIterator>(iter: I) -> FromIter<I::IntoIter> { + FromIter { iter: iter.into_iter() } +} + +#[unstable(feature = "async_iter_from_iter", issue = "81798")] +impl<I: Iterator> AsyncIterator for FromIter<I> { + type Item = I::Item; + + fn poll_next(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { + Poll::Ready(self.iter.next()) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + self.iter.size_hint() + } +} diff --git a/library/core/src/async_iter/mod.rs b/library/core/src/async_iter/mod.rs new file mode 100644 index 000000000..0c6f63771 --- /dev/null +++ b/library/core/src/async_iter/mod.rs @@ -0,0 +1,128 @@ +//! Composable asynchronous iteration. +//! +//! If you've found yourself with an asynchronous collection of some kind, +//! and needed to perform an operation on the elements of said collection, +//! you'll quickly run into 'async iterators'. Async Iterators are heavily used in +//! idiomatic asynchronous Rust code, so it's worth becoming familiar with them. +//! +//! Before explaining more, let's talk about how this module is structured: +//! +//! # Organization +//! +//! This module is largely organized by type: +//! +//! * [Traits] are the core portion: these traits define what kind of async iterators +//! exist and what you can do with them. The methods of these traits are worth +//! putting some extra study time into. +//! * Functions provide some helpful ways to create some basic async iterators. +//! * Structs are often the return types of the various methods on this +//! module's traits. You'll usually want to look at the method that creates +//! the `struct`, rather than the `struct` itself. For more detail about why, +//! see '[Implementing Async Iterator](#implementing-async-iterator)'. +//! +//! [Traits]: #traits +//! +//! That's it! Let's dig into async iterators. +//! +//! # Async Iterators +//! +//! The heart and soul of this module is the [`AsyncIterator`] trait. The core of +//! [`AsyncIterator`] looks like this: +//! +//! ``` +//! # use core::task::{Context, Poll}; +//! # use core::pin::Pin; +//! trait AsyncIterator { +//! type Item; +//! fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>; +//! } +//! ``` +//! +//! Unlike `Iterator`, `AsyncIterator` makes a distinction between the [`poll_next`] +//! method which is used when implementing an `AsyncIterator`, and a (to-be-implemented) +//! `next` method which is used when consuming an async iterator. Consumers of `AsyncIterator` +//! only need to consider `next`, which when called, returns a future which +//! yields `Option<AsyncIterator::Item>`. +//! +//! The future returned by `next` will yield `Some(Item)` as long as there are +//! elements, and once they've all been exhausted, will yield `None` to indicate +//! that iteration is finished. If we're waiting on something asynchronous to +//! resolve, the future will wait until the async iterator is ready to yield again. +//! +//! Individual async iterators may choose to resume iteration, and so calling `next` +//! again may or may not eventually yield `Some(Item)` again at some point. +//! +//! [`AsyncIterator`]'s full definition includes a number of other methods as well, +//! but they are default methods, built on top of [`poll_next`], and so you get +//! them for free. +//! +//! [`Poll`]: super::task::Poll +//! [`poll_next`]: AsyncIterator::poll_next +//! +//! # Implementing Async Iterator +//! +//! Creating an async iterator of your own involves two steps: creating a `struct` to +//! hold the async iterator's state, and then implementing [`AsyncIterator`] for that +//! `struct`. +//! +//! Let's make an async iterator named `Counter` which counts from `1` to `5`: +//! +//! ```no_run +//! #![feature(async_iterator)] +//! # use core::async_iter::AsyncIterator; +//! # use core::task::{Context, Poll}; +//! # use core::pin::Pin; +//! +//! // First, the struct: +//! +//! /// An async iterator which counts from one to five +//! struct Counter { +//! count: usize, +//! } +//! +//! // we want our count to start at one, so let's add a new() method to help. +//! // This isn't strictly necessary, but is convenient. Note that we start +//! // `count` at zero, we'll see why in `poll_next()`'s implementation below. +//! impl Counter { +//! fn new() -> Counter { +//! Counter { count: 0 } +//! } +//! } +//! +//! // Then, we implement `AsyncIterator` for our `Counter`: +//! +//! impl AsyncIterator for Counter { +//! // we will be counting with usize +//! type Item = usize; +//! +//! // poll_next() is the only required method +//! fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { +//! // Increment our count. This is why we started at zero. +//! self.count += 1; +//! +//! // Check to see if we've finished counting or not. +//! if self.count < 6 { +//! Poll::Ready(Some(self.count)) +//! } else { +//! Poll::Ready(None) +//! } +//! } +//! } +//! ``` +//! +//! # Laziness +//! +//! Async iterators are *lazy*. This means that just creating an async iterator doesn't +//! _do_ a whole lot. Nothing really happens until you call `poll_next`. This is +//! sometimes a source of confusion when creating an async iterator solely for its side +//! effects. The compiler will warn us about this kind of behavior: +//! +//! ```text +//! warning: unused result that must be used: async iterators do nothing unless polled +//! ``` + +mod async_iter; +mod from_iter; + +pub use async_iter::AsyncIterator; +pub use from_iter::{from_iter, FromIter}; |