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

Issue:
process_results on the Itertools trait
A typical use-case for process-results is e.g.
```rust
let final_map = itertools::process_results(
    some
        .long()
        .chain()
        .of()
        .iterator()
        .adapters(),
    |it| it.into_group_map(),
)?;
```

With the chain of iterator adapters getting longer and longer, this writing becomes less and less readable.

=> It would be much nicer to be able to write:
```rust
let final_map = some
    .long()
    .chain()
    .of()
    .iterator()
    .adapters()
    .process_results(|it| it.into_group_map())?;
```

This would be pretty easy to do by adding process_results in the `Itertools` trait.


Discussion / hints:

Fix patch:
diff --git a/src/lib.rs b/src/lib.rs
index f9cf0da7e..9f8b275c9 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -926,6 +926,43 @@ pub trait Itertools : Iterator {
         flatten_ok::flatten_ok(self)
     }
 
+    /// “Lift” a function of the values of the current iterator so as to process
+    /// an iterator of `Result` values instead.
+    ///
+    /// `processor` is a closure that receives an adapted version of the iterator
+    /// as the only argument — the adapted iterator produces elements of type `T`,
+    /// as long as the original iterator produces `Ok` values.
+    ///
+    /// If the original iterable produces an error at any point, the adapted
+    /// iterator ends and it will return the error iself.
+    ///
+    /// Otherwise, the return value from the closure is returned wrapped
+    /// inside `Ok`.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use itertools::Itertools;
+    ///
+    /// type Item = Result<i32, &'static str>;
+    ///
+    /// let first_values: Vec<Item> = vec![Ok(1), Ok(0), Ok(3)];
+    /// let second_values: Vec<Item> = vec![Ok(2), Ok(1), Err("overflow")];
+    ///
+    /// // “Lift” the iterator .max() method to work on the Ok-values.
+    /// let first_max = first_values.into_iter().process_results(|iter| iter.max().unwrap_or(0));
+    /// let second_max = second_values.into_iter().process_results(|iter| iter.max().unwrap_or(0));
+    ///
+    /// assert_eq!(first_max, Ok(3));
+    /// assert!(second_max.is_err());
+    /// ```
+    fn process_results<F, T, E, R>(self, processor: F) -> Result<R, E>
+        where Self: Iterator<Item = Result<T, E>> + Sized,
+              F: FnOnce(ProcessResults<Self, E>) -> R
+    {
+        process_results(self, processor)
+    }
+
     /// Return an iterator adaptor that merges the two base iterators in
     /// ascending order.  If both base iterators are sorted (ascending), the
     /// result is sorted.


Test patch: