From 2ce188aafbb0bafd7f369cfbe35d1504655141f7 Mon Sep 17 00:00:00 2001 From: joboet Date: Sat, 22 Mar 2025 14:01:43 +0100 Subject: [PATCH] core: implement `fold` via `try_fold` ... and `rfold` via `try_rfold`. It's not possible to implement `try_fold` via `fold`, so this cannot lead to recursion. While unfortunately `try_fold` cannot be currently implemented for user types on stable, it paves a path to a future where implementing a good `try_fold` is enough to make nearly all `Iterator` traversal methods perform optimally. r? libs-api --- library/alloc/src/collections/vec_deque/into_iter.rs | 10 ---------- library/core/src/iter/traits/double_ended.rs | 10 +++------- library/core/src/iter/traits/iterator.rs | 10 +++------- 3 files changed, 6 insertions(+), 24 deletions(-) diff --git a/library/alloc/src/collections/vec_deque/into_iter.rs b/library/alloc/src/collections/vec_deque/into_iter.rs index 2b09a5e7ddc58..17ac35d0bef91 100644 --- a/library/alloc/src/collections/vec_deque/into_iter.rs +++ b/library/alloc/src/collections/vec_deque/into_iter.rs @@ -114,16 +114,6 @@ impl Iterator for IntoIter { .try_fold(init, &mut f) } - #[inline] - fn fold(mut self, init: B, mut f: F) -> B - where - F: FnMut(B, Self::Item) -> B, - { - match self.try_fold(init, |b, item| Ok::(f(b, item))) { - Ok(b) => b, - } - } - #[inline] fn last(mut self) -> Option { self.inner.pop_back() diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs index 7dabaece95561..ecc5c5ca88883 100644 --- a/library/core/src/iter/traits/double_ended.rs +++ b/library/core/src/iter/traits/double_ended.rs @@ -1,5 +1,5 @@ use crate::num::NonZero; -use crate::ops::{ControlFlow, Try}; +use crate::ops::{ControlFlow, NeverShortCircuit, Try}; /// An iterator able to yield elements from both ends. /// @@ -298,16 +298,12 @@ pub trait DoubleEndedIterator: Iterator { #[doc(alias = "foldr")] #[inline] #[stable(feature = "iter_rfold", since = "1.27.0")] - fn rfold(mut self, init: B, mut f: F) -> B + fn rfold(mut self, init: B, f: F) -> B where Self: Sized, F: FnMut(B, Self::Item) -> B, { - let mut accum = init; - while let Some(x) = self.next_back() { - accum = f(accum, x); - } - accum + self.try_rfold(init, NeverShortCircuit::wrap_mut_2(f)).0 } /// Searches for an element of an iterator from the back that satisfies a predicate. diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 3bbb52fdbcb5f..7c9a64917c1b8 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -7,7 +7,7 @@ use super::super::{ use crate::array; use crate::cmp::{self, Ordering}; use crate::num::NonZero; -use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try}; +use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, NeverShortCircuit, Residual, Try}; fn _assert_is_dyn_compatible(_: &dyn Iterator) {} @@ -2550,16 +2550,12 @@ pub trait Iterator { #[doc(alias = "inject", alias = "foldl")] #[inline] #[stable(feature = "rust1", since = "1.0.0")] - fn fold(mut self, init: B, mut f: F) -> B + fn fold(mut self, init: B, f: F) -> B where Self: Sized, F: FnMut(B, Self::Item) -> B, { - let mut accum = init; - while let Some(x) = self.next() { - accum = f(accum, x); - } - accum + self.try_fold(init, NeverShortCircuit::wrap_mut_2(f)).0 } /// Reduces the elements to a single one, by repeatedly applying a reducing