Skip to content

Pinnediterator #1

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

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macOS-latest]
rust: [stable]
rust: [nightly]

steps:
- uses: actions/checkout@master
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ authors = [
[features]

[dependencies]
pin-project = "1.0.12"

[dev-dependencies]
129 changes: 129 additions & 0 deletions src/async_iter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
//! Async iterator support.

use std::future::Future;

/// An interface for dealing with iterators.
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub trait AsyncIterator {
/// The type of the elements being iterated over.
type Item;

/// Advances the iterator and returns the next value.
async fn next(&mut self) -> Option<Self::Item>;

/// Returns the bounds on the remaining length of the iterator.
fn size_hint(&self) -> (usize, Option<usize>) {
(0, None)
}

/// Takes a closure and creates an iterator which calls that closure on each element.
fn map<B, F>(self, f: F) -> AsyncMap<Self, F>
where
Self: Sized,
F: FnMut(Self::Item) -> B,
{
AsyncMap { stream: self, f }
}

/// Transforms an iterator into a collection.
// #[must_use = "if you really need to exhaust the iterator, consider `.for_each(drop)` instead"]
async fn collect<B: FromAsyncIterator<Self::Item>>(self) -> B
where
Self: Sized,
{
let fut = <B as FromAsyncIterator<_>>::from_iter(self);
fut.await
}
}

/// Conversion into an [`Iterator`].

pub trait IntoAsyncIterator {
/// The type of the elements being iterated over.
type Item;

/// Which kind of iterator are we turning this into?
type IntoIter: AsyncIterator<Item = Self::Item>;

/// Creates an iterator from a value.
async fn into_iter(self) -> Self::IntoIter;
}

impl<I: AsyncIterator> IntoAsyncIterator for I {
type Item = I::Item;
type IntoIter = I;

async fn into_iter(self) -> I {
self
}
}

/// Conversion from an [`Iterator`].

pub trait FromAsyncIterator<A>: Sized {
/// Creates a value from an iterator.
async fn from_iter<T: IntoAsyncIterator<Item = A>>(iter: T) -> Self;
}

impl<T> FromAsyncIterator<T> for Vec<T> {
async fn from_iter<I: IntoAsyncIterator<Item = T>>(iter: I) -> Vec<T> {
let mut iter = iter.into_iter().await;
let mut output = Vec::with_capacity(iter.size_hint().1.unwrap_or_default());
while let Some(item) = iter.next().await {
output.push(item);
}
output
}
}

/// Extend a collection with the contents of an iterator.

pub trait AsyncExtend<A> {
/// Extends a collection with the contents of an iterator.
async fn extend<T: IntoAsyncIterator<Item = A>>(&mut self, iter: T);
}

impl<T> AsyncExtend<T> for Vec<T> {
async fn extend<I: IntoAsyncIterator<Item = T>>(&mut self, iter: I) {
let mut iter = iter.into_iter().await;
self.reserve(iter.size_hint().1.unwrap_or_default());
while let Some(item) = iter.next().await {
self.push(item);
}
}
}

/// An iterator that maps value of another stream with a function.
#[derive(Debug)]
pub struct AsyncMap<I, F> {
stream: I,
f: F,
}

impl<I, F, B, Fut> AsyncIterator for AsyncMap<I, F>
where
I: AsyncIterator,
F: FnMut(I::Item) -> Fut,
Fut: Future<Output = B>,
{
type Item = B;

async fn next(&mut self) -> Option<Self::Item> {
let item = self.stream.next().await?;
let out = (self.f)(item).await;
Some(out)
}
}

#[cfg(test)]
mod test {
use super::*;

#[test]
fn smoke() {
#[allow(unused)]
async fn foo(iter: impl AsyncIterator<Item = u32>) {
let v: Vec<_> = iter.collect().await;
}
}
}
135 changes: 135 additions & 0 deletions src/async_pinned_iter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
//! Async self-referential (pinned) iterator support.

use std::future::Future;
use std::pin::{pin, Pin};

use pin_project::pin_project;

/// An interface for dealing with iterators.
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub trait AsyncPinnedIterator {
/// The type of the elements being iterated over.
type Item;

/// Advances the iterator and returns the next value.
async fn next(self: Pin<&mut Self>) -> Option<Self::Item>;

/// Returns the bounds on the remaining length of the iterator.
fn size_hint(&self) -> (usize, Option<usize>) {
(0, None)
}

/// Takes a closure and creates an iterator which calls that closure on each element.
fn map<B, F>(self, f: F) -> AsyncPinnedMap<Self, F>
where
Self: Sized,
F: FnMut(Self::Item) -> B,
{
AsyncPinnedMap { stream: self, f }
}

/// Transforms an iterator into a collection.
// #[must_use = "if you really need to exhaust the iterator, consider `.for_each(drop)` instead"]
async fn collect<B: FromAsyncPinnedIterator<Self::Item>>(self) -> B
where
Self: Sized,
{
let fut = <B as FromAsyncPinnedIterator<_>>::from_iter(self);
fut.await
}
}

/// Conversion into an [`Iterator`].

pub trait IntoAsyncPinnedIterator {
/// The type of the elements being iterated over.
type Item;

/// Which kind of iterator are we turning this into?
type IntoIter: AsyncPinnedIterator<Item = Self::Item>;

/// Creates an iterator from a value.
async fn into_iter(self) -> Self::IntoIter;
}

impl<I: AsyncPinnedIterator> IntoAsyncPinnedIterator for I {
type Item = I::Item;
type IntoIter = I;

async fn into_iter(self) -> I {
self
}
}

/// Conversion from an [`Iterator`].

pub trait FromAsyncPinnedIterator<A>: Sized {
/// Creates a value from an iterator.
async fn from_iter<T: IntoAsyncPinnedIterator<Item = A>>(iter: T) -> Self;
}

impl<T> FromAsyncPinnedIterator<T> for Vec<T> {
async fn from_iter<I: IntoAsyncPinnedIterator<Item = T>>(iter: I) -> Vec<T> {
let mut iter = pin!(iter.into_iter().await);
let mut output = Vec::with_capacity(iter.size_hint().1.unwrap_or_default());
while let Some(item) = iter.as_mut().next().await {
output.push(item);
}
output
}
}

/// Extend a collection with the contents of an iterator.

pub trait AsyncPinnedExtend<A> {
/// Extends a collection with the contents of an iterator.
async fn extend<T: IntoAsyncPinnedIterator<Item = A>>(&mut self, iter: T);
}

impl<T> AsyncPinnedExtend<T> for Vec<T> {
async fn extend<I: IntoAsyncPinnedIterator<Item = T>>(&mut self, iter: I) {
let mut iter = pin!(iter.into_iter().await);
self.reserve(iter.size_hint().1.unwrap_or_default());
while let Some(item) = iter.as_mut().next().await {
self.push(item);
}
}
}

/// An iterator that maps value of another stream with a function.
#[derive(Debug)]
#[pin_project]
pub struct AsyncPinnedMap<I, F> {
#[pin]
stream: I,
f: F,
}

impl<I, F, B, Fut> AsyncPinnedIterator for AsyncPinnedMap<I, F>
where
I: AsyncPinnedIterator,
F: FnMut(I::Item) -> Fut,
Fut: Future<Output = B>,
{
type Item = B;

async fn next(self: Pin<&mut Self>) -> Option<Self::Item> {
let this = self.project();
let item = this.stream.next().await?;
let out = (this.f)(item).await;
Some(out)
}
}

#[cfg(test)]
mod test {
use super::*;

#[test]
fn smoke() {
#[allow(unused)]
async fn foo(iter: impl AsyncPinnedIterator<Item = u32>) {
let v: Vec<_> = iter.collect().await;
}
}
}
Loading