@@ -15,7 +15,7 @@ use futures_core::stream::TryStream;
15
15
#[ cfg( feature = "alloc" ) ]
16
16
use futures_core:: stream:: { BoxStream , LocalBoxStream } ;
17
17
use futures_core:: {
18
- future:: Future ,
18
+ future:: { Future , TryFuture } ,
19
19
stream:: { FusedStream , Stream } ,
20
20
task:: { Context , Poll } ,
21
21
} ;
@@ -149,6 +149,14 @@ mod then;
149
149
#[ allow( unreachable_pub) ] // https://github.com/rust-lang/rust/issues/57411
150
150
pub use self :: then:: Then ;
151
151
152
+ mod try_for_each;
153
+ #[ allow( unreachable_pub) ] // https://github.com/rust-lang/rust/issues/57411
154
+ pub use self :: try_for_each:: TryForEach ;
155
+
156
+ mod try_fold;
157
+ #[ allow( unreachable_pub) ] // https://github.com/rust-lang/rust/issues/57411
158
+ pub use self :: try_fold:: TryFold ;
159
+
152
160
mod zip;
153
161
#[ allow( unreachable_pub) ] // https://github.com/rust-lang/rust/issues/57411
154
162
pub use self :: zip:: Zip ;
@@ -197,6 +205,12 @@ cfg_target_has_atomic! {
197
205
#[ cfg( feature = "alloc" ) ]
198
206
#[ allow( unreachable_pub) ] // https://github.com/rust-lang/rust/issues/57411
199
207
pub use self :: split:: { SplitStream , SplitSink , ReuniteError } ;
208
+
209
+ #[ cfg( feature = "alloc" ) ]
210
+ mod try_for_each_concurrent;
211
+ #[ cfg( feature = "alloc" ) ]
212
+ #[ allow( unreachable_pub) ] // https://github.com/rust-lang/rust/issues/57411
213
+ pub use self :: try_for_each_concurrent:: TryForEachConcurrent ;
200
214
}
201
215
202
216
#[ cfg( feature = "std" ) ]
@@ -934,6 +948,145 @@ pub trait StreamExt: Stream {
934
948
assert_future :: < ( ) , _ > ( ForEachConcurrent :: new ( self , limit. into ( ) , f) )
935
949
}
936
950
951
+ /// Attempt to execute an accumulating asynchronous computation over a
952
+ /// stream, collecting all the values into one final result.
953
+ ///
954
+ /// This combinator will accumulate all values returned by this stream
955
+ /// according to the closure provided. The initial state is also provided to
956
+ /// this method and then is returned again by each execution of the closure.
957
+ /// Once the entire stream has been exhausted the returned future will
958
+ /// resolve to this value.
959
+ ///
960
+ /// This method is similar to [`fold`](crate::stream::StreamExt::fold), but will
961
+ /// exit early if an error is encountered in either the stream or the
962
+ /// provided closure.
963
+ ///
964
+ /// # Examples
965
+ ///
966
+ /// ```
967
+ /// # futures::executor::block_on(async {
968
+ /// use futures::stream::{self, StreamExt};
969
+ ///
970
+ /// let number_stream = stream::iter(vec![1, 2]);
971
+ /// let sum = number_stream.try_fold(0, |acc, x| async move { Ok::<i32, i32>(acc + x) });
972
+ /// assert_eq!(sum.await, Ok(3));
973
+ ///
974
+ /// let number_stream_with_err = stream::iter(vec![Ok::<i32, i32>(1), Err(2), Ok(1)]);
975
+ /// let sum = number_stream_with_err.try_fold(0, |acc, x| async move { Ok(acc + x?) });
976
+ /// assert_eq!(sum.await, Err(2));
977
+ /// # })
978
+ /// ```
979
+ fn try_fold < T , Fut , F > ( self , init : T , f : F ) -> TryFold < Self , Fut , T , F >
980
+ where
981
+ F : FnMut ( T , Self :: Item ) -> Fut ,
982
+ Fut : TryFuture < Ok = T > ,
983
+ Self : Sized ,
984
+ {
985
+ assert_future :: < Result < T , Fut :: Error > , _ > ( TryFold :: new ( self , f, init) )
986
+ }
987
+
988
+ /// Attempts to run this stream to completion, executing the provided
989
+ /// asynchronous closure for each element on the stream.
990
+ ///
991
+ /// The provided closure will be called for each item this stream produces,
992
+ /// yielding a future. That future will then be executed to completion
993
+ /// before moving on to the next item.
994
+ ///
995
+ /// The returned value is a [`Future`](futures_core::future::Future) where the
996
+ /// [`Output`](futures_core::future::Future::Output) type is
997
+ /// `Result<(), Self::Error>`. If any of the intermediate
998
+ /// futures or the stream returns an error, this future will return
999
+ /// immediately with an error.
1000
+ ///
1001
+ /// # Examples
1002
+ ///
1003
+ /// ```
1004
+ /// # futures::executor::block_on(async {
1005
+ /// use futures::future;
1006
+ /// use futures::stream::{self, StreamExt};
1007
+ ///
1008
+ /// let mut x = 0i32;
1009
+ ///
1010
+ /// {
1011
+ /// let fut = stream::repeat(1).try_for_each(|item| {
1012
+ /// x += item;
1013
+ /// future::ready(if x == 3 { Err(()) } else { Ok(()) })
1014
+ /// });
1015
+ /// assert_eq!(fut.await, Err(()));
1016
+ /// }
1017
+ ///
1018
+ /// assert_eq!(x, 3);
1019
+ /// # })
1020
+ /// ```
1021
+ fn try_for_each < Fut , F > ( self , f : F ) -> TryForEach < Self , Fut , F >
1022
+ where
1023
+ F : FnMut ( Self :: Item ) -> Fut ,
1024
+ Fut : TryFuture < Ok = ( ) > ,
1025
+ Self : Sized ,
1026
+ {
1027
+ assert_future :: < Result < ( ) , Fut :: Error > , _ > ( TryForEach :: new ( self , f) )
1028
+ }
1029
+
1030
+ /// Attempts to run this stream to completion, executing the provided asynchronous
1031
+ /// closure for each element on the stream concurrently as elements become
1032
+ /// available, exiting as soon as an error occurs.
1033
+ ///
1034
+ /// This is similar to
1035
+ /// [`StreamExt::for_each_concurrent`](crate::stream::StreamExt::for_each_concurrent),
1036
+ /// but will resolve to an error immediately if the underlying stream or the provided
1037
+ /// closure return an error.
1038
+ ///
1039
+ /// This method is only available when the `std` or `alloc` feature of this
1040
+ /// library is activated, and it is activated by default.
1041
+ ///
1042
+ /// # Examples
1043
+ ///
1044
+ /// ```
1045
+ /// # futures::executor::block_on(async {
1046
+ /// use futures::channel::oneshot;
1047
+ /// use futures::stream::{self, StreamExt};
1048
+ ///
1049
+ /// let (tx1, rx1) = oneshot::channel();
1050
+ /// let (tx2, rx2) = oneshot::channel();
1051
+ /// let (_tx3, rx3) = oneshot::channel();
1052
+ ///
1053
+ /// let stream = stream::iter(vec![rx1, rx2, rx3]);
1054
+ /// let fut = stream.try_for_each_concurrent(
1055
+ /// /* limit */ 2,
1056
+ /// |rx| async move {
1057
+ /// let res: Result<(), oneshot::Canceled> = rx.await;
1058
+ /// res
1059
+ /// }
1060
+ /// );
1061
+ ///
1062
+ /// tx1.send(()).unwrap();
1063
+ /// // Drop the second sender so that `rx2` resolves to `Canceled`.
1064
+ /// drop(tx2);
1065
+ ///
1066
+ /// // The final result is an error because the second future
1067
+ /// // resulted in an error.
1068
+ /// assert_eq!(Err(oneshot::Canceled), fut.await);
1069
+ /// # })
1070
+ /// ```
1071
+ #[ cfg_attr( feature = "cfg-target-has-atomic" , cfg( target_has_atomic = "ptr" ) ) ]
1072
+ #[ cfg( feature = "alloc" ) ]
1073
+ fn try_for_each_concurrent < Fut , F , E > (
1074
+ self ,
1075
+ limit : impl Into < Option < usize > > ,
1076
+ f : F ,
1077
+ ) -> TryForEachConcurrent < Self , Fut , F >
1078
+ where
1079
+ F : FnMut ( Self :: Item ) -> Fut ,
1080
+ Fut : Future < Output = Result < ( ) , E > > ,
1081
+ Self : Sized ,
1082
+ {
1083
+ assert_future :: < Result < ( ) , E > , _ > ( TryForEachConcurrent :: new (
1084
+ self ,
1085
+ limit. into ( ) ,
1086
+ f,
1087
+ ) )
1088
+ }
1089
+
937
1090
/// Creates a new stream of at most `n` items of the underlying stream.
938
1091
///
939
1092
/// Once `n` items have been yielded from this stream then it will always
0 commit comments