stream: add StreamExt::fold() (#2122)

This commit is contained in:
Artem Vorotnikov
2020-01-23 09:03:10 -08:00
committed by Carl Lerche
parent 8cf98d6946
commit 0545b349e1
2 changed files with 78 additions and 0 deletions
+51
View File
@@ -0,0 +1,51 @@
use crate::stream::Stream;
use core::future::Future;
use core::pin::Pin;
use core::task::{Context, Poll};
use pin_project_lite::pin_project;
pin_project! {
/// Future returned by the [`fold`](super::StreamExt::fold) method.
#[derive(Debug)]
pub struct FoldFuture<St, B, F> {
#[pin]
stream: St,
acc: Option<B>,
f: F,
}
}
impl<St, B, F> FoldFuture<St, B, F> {
pub(super) fn new(stream: St, init: B, f: F) -> Self {
Self {
stream,
acc: Some(init),
f,
}
}
}
impl<St, B, F> Future for FoldFuture<St, B, F>
where
St: Stream,
F: FnMut(B, St::Item) -> B,
{
type Output = B;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let mut me = self.project();
loop {
let next = ready!(me.stream.as_mut().poll_next(cx));
match next {
Some(v) => {
let old = me.acc.take().unwrap();
let new = (me.f)(old, v);
*me.acc = Some(new);
}
None => return Poll::Ready(me.acc.take().unwrap()),
}
}
}
}
+27
View File
@@ -26,6 +26,9 @@ use filter::Filter;
mod filter_map;
use filter_map::FilterMap;
mod fold;
use fold::FoldFuture;
mod fuse;
use fuse::Fuse;
@@ -582,6 +585,30 @@ pub trait StreamExt: Stream {
Chain::new(self, other)
}
/// A combinator that applies a function to every element in a stream
/// producing a single, final value.
///
/// # Examples
/// Basic usage:
/// ```
/// # #[tokio::main]
/// # async fn main() {
/// use tokio::stream::{self, *};
///
/// let s = stream::iter(vec![1u8, 2, 3]);
/// let sum = s.fold(0, |acc, x| acc + x).await;
///
/// assert_eq!(sum, 6);
/// # }
/// ```
fn fold<B, F>(self, init: B, f: F) -> FoldFuture<Self, B, F>
where
Self: Sized,
F: FnMut(B, Self::Item) -> B,
{
FoldFuture::new(self, init, f)
}
/// Drain stream pushing all emitted values into a collection.
///
/// `collect` streams all values, awaiting as needed. Values are pushed into