Repository: rust-itertools/itertools (language: rust)

Issue:
process_results is lacking a lot of function specializations
fold/try_fold are missing on the iterator adapter, resulting in a lot of underlying implementations possibly being slower (including in particular collect/into_group_map, etc...).

I believe we should just copy over the standard library's implementation (that's actually used in `FromIterator<Result<T,E>> for Result<Collection, E> where Collection<FromIterator<T>>`):
https://github.com/rust-lang/rust/blob/68511b574ffe019a5cb3e9fa92605f80d39167bc/library/core/src/iter/adapters/mod.rs#L125-L197


Discussion / hints:

Fix patch:
diff --git a/src/process_results_impl.rs b/src/process_results_impl.rs
index 9da108b15..44308f378 100644
--- a/src/process_results_impl.rs
+++ b/src/process_results_impl.rs
@@ -30,6 +30,23 @@ impl<'a, I, T, E> Iterator for ProcessResults<'a, I, E>
     fn size_hint(&self) -> (usize, Option<usize>) {
         (0, self.iter.size_hint().1)
     }
+
+    fn fold<B, F>(mut self, init: B, mut f: F) -> B
+    where
+        Self: Sized,
+        F: FnMut(B, Self::Item) -> B,
+    {
+        let error = self.error;
+        self.iter
+            .try_fold(init, |acc, opt| match opt {
+                Ok(x) => Ok(f(acc, x)),
+                Err(e) => {
+                    *error = Err(e);
+                    Err(acc)
+                }
+            })
+            .unwrap_or_else(|e| e)
+    }
 }
 
 /// “Lift” a function of the values of an iterator so that it can process


Test patch:
diff --git a/tests/specializations.rs b/tests/specializations.rs
index bc337c28e..6a1d0cffb 100644
--- a/tests/specializations.rs
+++ b/tests/specializations.rs
@@ -98,3 +98,50 @@ quickcheck! {
         test_specializations(&v.into_iter().map_ok(|u| u.checked_add(1)));
     }
 }
+
+quickcheck! {
+    fn process_results(v: Vec<Result<u8, u8>>) -> () {
+        helper(v.iter().copied());
+        helper(v.iter().copied().filter(Result::is_ok));
+
+        fn helper(it: impl Iterator<Item = Result<u8, u8>> + Clone) {
+            macro_rules! check_results_specialized {
+                ($src:expr, |$it:pat| $closure:expr) => {
+                    assert_eq!(
+                        itertools::process_results($src.clone(), |$it| $closure),
+                        itertools::process_results($src.clone(), |i| {
+                            let $it = Unspecialized(i);
+                            $closure
+                        }),
+                    )
+                }
+            }
+
+            check_results_specialized!(it, |i| i.count());
+            check_results_specialized!(it, |i| i.last());
+            check_results_specialized!(it, |i| i.collect::<Vec<_>>());
+            check_results_specialized!(it, |i| {
+                let mut parameters_from_fold = vec![];
+                let fold_result = i.fold(vec![], |mut acc, v| {
+                    parameters_from_fold.push((acc.clone(), v.clone()));
+                    acc.push(v);
+                    acc
+                });
+                (parameters_from_fold, fold_result)
+            });
+            check_results_specialized!(it, |mut i| {
+                let mut parameters_from_all = vec![];
+                let first = i.next();
+                let all_result = i.all(|x| {
+                    parameters_from_all.push(x.clone());
+                    Some(x)==first
+                });
+                (parameters_from_all, all_result)
+            });
+            let size = it.clone().count();
+            for n in 0..size + 2 {
+                check_results_specialized!(it, |mut i| i.nth(n));
+            }
+        }
+    }
+}