resiter/try_filter.rs
1//
2// This Source Code Form is subject to the terms of the Mozilla Public
3// License, v. 2.0. If a copy of the MPL was not distributed with this
4// file, You can obtain one at http://mozilla.org/MPL/2.0/.
5//
6
7/// Extension for `Iterator<Item = Result<O, E>>` to filter the Ok(_) and leaving the Err(_) as
8/// is, but allowing the filter to return a `Result<bool, E>` itself
9pub trait TryFilter<O, E>: Sized {
10 /// Filters every `Ok`-value with a function that can return an Err.
11 /// Useful when the filter condition uses functions that can fail.
12 ///
13 ///```
14 /// use resiter::try_filter::TryFilter;
15 /// use std::str::FromStr;
16 ///
17 /// let v = ["1", "2", "4", "a", "5"]
18 /// .iter()
19 /// .map(Ok)
20 /// .try_filter_ok(|e| usize::from_str(e).map(|n| n < 3))
21 /// .collect::<Vec<Result<_, _>>>();
22 ///
23 /// assert_eq!(v.len(), 3);
24 /// assert_eq!(v.iter().filter(|x| x.is_ok()).count(), 2);
25 /// assert_eq!(v.iter().filter(|x| x.is_err()).count(), 1);
26 ///```
27 fn try_filter_ok<F>(self, _: F) -> TryFilterOk<Self, F>
28 where
29 F: FnMut(&O) -> Result<bool, E>;
30
31 /// Filters every `Err`-value with a function that can return an Err.
32 /// Useful when the filter condition uses functions that can fail.
33 ///
34 /// ```
35 /// use resiter::try_filter::TryFilter;
36 /// use std::num::ParseIntError;
37 /// use std::str::FromStr;
38 ///
39 /// let v = ["1", "2", "4", "a", "5"]
40 /// .iter()
41 /// .map(|txt| usize::from_str(txt))
42 /// .try_filter_err(|_:&ParseIntError| Ok(false))
43 /// .collect::<Vec<Result<_, _>>>();
44 ///
45 /// assert_eq!(v.iter().filter(|x| x.is_ok()).count(), 4);
46 /// assert_eq!(v.iter().filter(|x| x.is_err()).count(), 0);
47 /// ```
48 fn try_filter_err<F>(self, _: F) -> TryFilterErr<Self, F>
49 where
50 F: FnMut(&E) -> Result<bool, E>;
51}
52
53impl<I, O, E> TryFilter<O, E> for I
54where
55 I: Iterator<Item = Result<O, E>> + Sized,
56{
57 #[inline]
58 fn try_filter_ok<F>(self, f: F) -> TryFilterOk<Self, F>
59 where
60 F: FnMut(&O) -> Result<bool, E>,
61 {
62 TryFilterOk { iter: self, f }
63 }
64
65 #[inline]
66 fn try_filter_err<F>(self, f: F) -> TryFilterErr<Self, F>
67 where
68 F: FnMut(&E) -> Result<bool, E>,
69 {
70 TryFilterErr { iter: self, f }
71 }
72}
73
74#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
75pub struct TryFilterOk<I, F> {
76 iter: I,
77 f: F,
78}
79
80#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
81pub struct TryFilterErr<I, F> {
82 iter: I,
83 f: F,
84}
85
86impl<I, O, E, F> Iterator for TryFilterOk<I, F>
87where
88 I: Iterator<Item = Result<O, E>>,
89 F: FnMut(&O) -> Result<bool, E>,
90{
91 type Item = Result<O, E>;
92
93 fn next(&mut self) -> Option<Self::Item> {
94 loop {
95 return match self.iter.next() {
96 Some(Ok(x)) => match (self.f)(&x) {
97 Ok(true) => Some(Ok(x)),
98 Ok(false) => continue,
99 Err(e) => Some(Err(e)),
100 },
101 other => other,
102 };
103 }
104 }
105
106 #[inline]
107 fn size_hint(&self) -> (usize, Option<usize>) {
108 let hint_sup = self.iter.size_hint().1;
109 (0, hint_sup)
110 }
111}
112
113impl<I, O, E, F> Iterator for TryFilterErr<I, F>
114where
115 I: Iterator<Item = Result<O, E>>,
116 F: FnMut(&E) -> Result<bool, E>,
117{
118 type Item = Result<O, E>;
119
120 fn next(&mut self) -> Option<Self::Item> {
121 loop {
122 return match self.iter.next() {
123 Some(Err(x)) => match (self.f)(&x) {
124 Ok(true) => Some(Err(x)),
125 Ok(false) => continue,
126 Err(e) => Some(Err(e)),
127 },
128 other => other,
129 };
130 }
131 }
132
133 #[inline]
134 fn size_hint(&self) -> (usize, Option<usize>) {
135 let hint_sup = self.iter.size_hint().1;
136 (0, hint_sup)
137 }
138}