Repository: rust-itertools/itertools
Pull request #950 (2024-05-27 20:44:21)

feat(`FilterMapOk`): implement `DoubleEndedIterator`
`DoubleEndedIterator` implementation for `FilterMapOk` analog to #948.

Hope `rev()` is the right thing here, as `rfind_map` does not exist (#949).

Refs: #947

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/rust-itertools/itertools/pull/950?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 94.42%. Comparing base [(`6814180`)](https://app.codecov.io/gh/rust-itertools/itertools/commit/68141809aabec2816d3250820c8d6608f3b2293f?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) to head [(`dd1a88a`)](https://app.codecov.io/gh/rust-itertools/itertools/commit/dd1a88a0fade9d04253d9058aa23b1cdd224be72?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None).
> Report is 98 commits behind head on master.

> :exclamation: **Current head dd1a88a differs from pull request most recent head aa547c6**
> 
> Please [upload](https://docs.codecov.com/docs/codecov-uploader) reports for the commit aa547c6 to get more accurate results.


<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##           master     #950      +/-   ##
==========================================
+ Coverage   94.38%   94.42%   +0.03%     
==========================================
  Files          48       49       +1     
  Lines        6665     7046     +381     
==========================================
+ Hits         6291     6653     +362     
- Misses        374      393      +19     
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/rust-itertools/itertools/pull/950?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None).

Xenira: > You did not need to make a merge commit.

Wanted to rebase, but messed up. Like my pr's to be up to date :)



Patch:
diff --git a/benches/specializations.rs b/benches/specializations.rs
index 958bcc1..3a5d803 100644
--- a/benches/specializations.rs
+++ b/benches/specializations.rs
@@ -648,6 +648,7 @@ bench_specializations! {
         v.iter().copied().filter_ok(|x| x % 3 == 0)
     }
     filter_map_ok {
+        DoubleEndedIterator
         {
             let v = black_box((0_u32..1024)
                 .map(|x| if x % 2 == 1 { Err(x) } else { Ok(x) })
diff --git a/src/adaptors/mod.rs b/src/adaptors/mod.rs
index e757837..095b089 100644
--- a/src/adaptors/mod.rs
+++ b/src/adaptors/mod.rs
@@ -1041,6 +1041,30 @@ where
     }
 }
 
+impl<I, F, T, U, E> DoubleEndedIterator for FilterMapOk<I, F>
+where
+    I: DoubleEndedIterator<Item = Result<T, E>>,
+    F: FnMut(T) -> Option<U>,
+{
+    fn next_back(&mut self) -> Option<Self::Item> {
+        let f = &mut self.f;
+        self.iter.by_ref().rev().find_map(|res| match res {
+            Ok(t) => f(t).map(Ok),
+            Err(e) => Some(Err(e)),
+        })
+    }
+
+    fn rfold<Acc, Fold>(self, init: Acc, fold_f: Fold) -> Acc
+    where
+        Fold: FnMut(Acc, Self::Item) -> Acc,
+    {
+        let mut f = self.f;
+        self.iter
+            .filter_map(|v| transpose_result(v.map(&mut f)))
+            .rfold(init, fold_f)
+    }
+}
+
 impl<I, F, T, U, E> FusedIterator for FilterMapOk<I, F>
 where
     I: FusedIterator<Item = Result<T, E>>,


Test patch:
diff --git a/tests/specializations.rs b/tests/specializations.rs
index cdc51fb..ff3d5c1 100644
--- a/tests/specializations.rs
+++ b/tests/specializations.rs
@@ -453,7 +453,9 @@ quickcheck! {
     }
 
     fn filter_map_ok(v: Vec<Result<u8, char>>) -> () {
-        test_specializations(&v.into_iter().filter_map_ok(|i| if i < 20 { Some(i * 2) } else { None }));
+        let it = v.into_iter().filter_map_ok(|i| if i < 20 { Some(i * 2) } else { None });
+        test_specializations(&it);
+        test_double_ended_specializations(&it);
     }
 
     // `SmallIter2<u8>` because `Vec<u8>` is too slow and we get bad coverage from a singleton like Option<u8>