Skip to content

Commit fa73016

Browse files
committed
try_fold_first
1 parent d3d163a commit fa73016

File tree

1 file changed

+77
-9
lines changed

1 file changed

+77
-9
lines changed

library/core/src/iter/traits/iterator.rs

Lines changed: 77 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2525,15 +2525,7 @@ pub trait Iterator {
25252525
R: Try<Output = Self::Item>,
25262526
R::Residual: Residual<Option<Self::Item>>,
25272527
{
2528-
let first = match self.next() {
2529-
Some(i) => i,
2530-
None => return Try::from_output(None),
2531-
};
2532-
2533-
match self.try_fold(first, f).branch() {
2534-
ControlFlow::Break(r) => FromResidual::from_residual(r),
2535-
ControlFlow::Continue(i) => Try::from_output(Some(i)),
2536-
}
2528+
self.try_fold_first(Try::from_output, f)
25372529
}
25382530

25392531
/// Folds every element into an accumulator by applying an operation,
@@ -2583,6 +2575,82 @@ pub trait Iterator {
25832575
Some(self.fold(first, folding))
25842576
}
25852577

2578+
/// Folds every element into an accumulator by applying an operation,
2579+
/// returning the final result. The initial value is derived from the
2580+
/// first element using the provided method.
2581+
///
2582+
/// If the closure returns a failure, the failure is propagated back to the caller immediately.
2583+
///
2584+
/// # Example
2585+
///
2586+
/// Replaying a series of events from creation
2587+
///
2588+
/// ```
2589+
/// #![feature(iterator_try_fold_first)]
2590+
///
2591+
/// enum Events {
2592+
/// Create,
2593+
/// Update,
2594+
/// }
2595+
///
2596+
/// let events = [Events::Create, Events::Update, Events::Update];
2597+
/// let replayed_state = events.into_iter()
2598+
/// .try_fold_first(
2599+
/// |first| match first {
2600+
/// Events::Create => Ok(1),
2601+
/// _ => Err("only creation event supported at start"),
2602+
/// },
2603+
/// |state, next| match next {
2604+
/// Events::Update => Ok(state + 1),
2605+
/// _ => Err("only update events should follow a creation"),
2606+
/// },
2607+
/// );
2608+
/// assert_eq!(replayed_state, Ok(Some(3)));
2609+
///
2610+
/// // Which is equivalent to doing it with `try_fold`:
2611+
/// let events = [Events::Create, Events::Update, Events::Update];
2612+
/// let folded = events.into_iter()
2613+
/// .try_fold(
2614+
/// None,
2615+
/// |state, event| {
2616+
/// match (state, event) {
2617+
/// // init
2618+
/// (None, Events::Create) => Ok(Some(1)),
2619+
/// (None, Events::Update) => Err("only update events should follow a creation"),
2620+
///
2621+
/// // fold
2622+
/// (Some(state), Events::Update) => Ok(Some(state + 1)),
2623+
/// (Some(_), Events::Create) => Err("only creation event supported at start"),
2624+
/// }
2625+
/// },
2626+
/// );
2627+
/// assert_eq!(replayed_state, folded);
2628+
/// ```
2629+
#[inline]
2630+
#[unstable(feature = "iterator_try_fold_first", reason = "new API", issue = "none")]
2631+
fn try_fold_first<F1, FR, R>(
2632+
&mut self,
2633+
init: F1,
2634+
folding: FR,
2635+
) -> ChangeOutputType<R, Option<R::Output>>
2636+
where
2637+
Self: Sized,
2638+
F1: FnOnce(Self::Item) -> R,
2639+
FR: FnMut(R::Output, Self::Item) -> R,
2640+
R: Try,
2641+
R::Residual: Residual<Option<R::Output>>,
2642+
{
2643+
let first = match self.next() {
2644+
Some(i) => init(i)?,
2645+
None => return Try::from_output(None),
2646+
};
2647+
2648+
match self.try_fold(first, folding).branch() {
2649+
ControlFlow::Break(r) => FromResidual::from_residual(r),
2650+
ControlFlow::Continue(i) => Try::from_output(Some(i)),
2651+
}
2652+
}
2653+
25862654
/// Tests if every element of the iterator matches a predicate.
25872655
///
25882656
/// `all()` takes a closure that returns `true` or `false`. It applies

0 commit comments

Comments
 (0)