Skip to content

Commit 60a62f9

Browse files
bors[bot]montekki
andauthored
Merge #180
180: adds stream::fold combinator r=stjepang a=montekki Fold. Kind of clumsy around the part with the option and moving out of the shared context. ___ Stdlib: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.fold Ref: #129 Co-authored-by: Fedor Sakharov <[email protected]>
2 parents 08d954b + efe3516 commit 60a62f9

File tree

2 files changed

+83
-0
lines changed

2 files changed

+83
-0
lines changed

src/stream/stream/fold.rs

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
use std::marker::PhantomData;
2+
use std::pin::Pin;
3+
4+
use crate::future::Future;
5+
use crate::stream::Stream;
6+
use crate::task::{Context, Poll};
7+
8+
#[doc(hidden)]
9+
#[allow(missing_debug_implementations)]
10+
pub struct FoldFuture<S, F, T, B> {
11+
stream: S,
12+
f: F,
13+
acc: Option<B>,
14+
__t: PhantomData<T>,
15+
}
16+
17+
impl<S, F, T, B> FoldFuture<S, F, T, B> {
18+
pin_utils::unsafe_pinned!(stream: S);
19+
pin_utils::unsafe_unpinned!(f: F);
20+
pin_utils::unsafe_unpinned!(acc: Option<B>);
21+
22+
pub(super) fn new(stream: S, init: B, f: F) -> Self {
23+
FoldFuture {
24+
stream,
25+
f,
26+
acc: Some(init),
27+
__t: PhantomData,
28+
}
29+
}
30+
}
31+
32+
impl<S, F, B> Future for FoldFuture<S, F, S::Item, B>
33+
where
34+
S: Stream + Sized,
35+
F: FnMut(B, S::Item) -> B,
36+
{
37+
type Output = B;
38+
39+
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
40+
loop {
41+
let next = futures_core::ready!(self.as_mut().stream().poll_next(cx));
42+
43+
match next {
44+
Some(v) => {
45+
let old = self.as_mut().acc().take().unwrap();
46+
let new = (self.as_mut().f())(old, v);
47+
*self.as_mut().acc() = Some(new);
48+
}
49+
None => return Poll::Ready(self.as_mut().acc().take().unwrap()),
50+
}
51+
}
52+
}
53+
}

src/stream/stream/mod.rs

+30
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ mod enumerate;
2727
mod filter_map;
2828
mod find;
2929
mod find_map;
30+
mod fold;
3031
mod min_by;
3132
mod next;
3233
mod nth;
@@ -44,6 +45,7 @@ use enumerate::Enumerate;
4445
use filter_map::FilterMap;
4546
use find::FindFuture;
4647
use find_map::FindMapFuture;
48+
use fold::FoldFuture;
4749
use min_by::MinByFuture;
4850
use next::NextFuture;
4951
use nth::NthFuture;
@@ -481,6 +483,34 @@ pub trait Stream {
481483
FindMapFuture::new(self, f)
482484
}
483485

486+
/// A combinator that applies a function to every element in a stream
487+
/// producing a single, final value.
488+
///
489+
/// # Examples
490+
///
491+
/// Basic usage:
492+
///
493+
/// ```
494+
/// # fn main() { async_std::task::block_on(async {
495+
/// #
496+
/// use async_std::prelude::*;
497+
/// use std::collections::VecDeque;
498+
///
499+
/// let s: VecDeque<usize> = vec![1, 2, 3].into_iter().collect();
500+
/// let sum = s.fold(0, |acc, x| acc + x).await;
501+
///
502+
/// assert_eq!(sum, 6);
503+
/// #
504+
/// # }) }
505+
/// ```
506+
fn fold<B, F>(self, init: B, f: F) -> FoldFuture<Self, F, Self::Item, B>
507+
where
508+
Self: Sized,
509+
F: FnMut(B, Self::Item) -> B,
510+
{
511+
FoldFuture::new(self, init, f)
512+
}
513+
484514
/// Tests if any element of the stream matches a predicate.
485515
///
486516
/// `any()` takes a closure that returns `true` or `false`. It applies

0 commit comments

Comments
 (0)