try_all/map.rs
1type Recollector<T> = std::vec::IntoIter<T>;
2
3/// Trait providing try map (result) extensions to Iterators.
4///
5/// See [`TryMapAll::try_map_all`].
6///
7/// Once `Try` (#42327) is stabilized, hopefully the `Result` and `Option` variants can be merged and generalized.
8pub trait TryMapAll {
9 type Item;
10 /// Applies a closure on all items of the iterator until one fails (or all succeed).
11 ///
12 /// # Arguments
13 ///
14 /// - `f`: fallible mapping function
15 ///
16 /// # Returns
17 ///
18 /// The iterator of all successes, or the first failure.
19 ///
20 /// # Examples
21 ///
22 /// Useful for propagating failures from within closures with `?` operator:
23 /// ```rust
24 /// # use crate::try_all::*;
25 /// fn all_numbers_x2(strs: &Vec<&str>) -> Result<Vec<u64>, std::num::ParseIntError> {
26 /// Ok(strs.iter().try_map_all(|s| Ok(s.parse::<u64>()?*2))?.collect())
27 /// }
28 /// ```
29 ///
30 /// # Equivalence
31 ///
32 /// `iter.try_map_all(f)` is equivalent to `iter.map(f).try_all()`, except the latter works with `Option`s just as well (or check out [`TryMapAllOption::try_map_all_opt()`]).
33 ///
34 /// Additionally, it is equivalent to
35 /// ```rust
36 /// # fn hehe<U, T, E>(iter: impl Iterator<Item=U>, f: impl Fn(U) -> Result<T, E>) -> Result<Vec<T>, E> {
37 /// let mut acc = Vec::new();
38 /// for item in iter {
39 /// acc.push(f(item)?);
40 /// }
41 /// Ok(acc)
42 /// # }
43 /// ```
44 ///
45 /// Due to the nature of operation, the function has to collect intermediate results.
46 /// In other words, if `f` has side effects, expect them for all applications until \[including\] first failure.
47 /// Additionally, this won't work on infinite sequences :o.
48 fn try_map_all<T, E>(self, f: impl Fn(Self::Item) -> Result<T, E>) -> Result<Recollector<T>, E>;
49}
50
51impl<I: Iterator> TryMapAll for I {
52 type Item = I::Item;
53 fn try_map_all<T, E>(self, f: impl Fn(Self::Item) -> Result<T, E>) -> Result<Recollector<T>, E> {
54 let mut ok = Vec::new();
55 for t in self {
56 ok.push(f(t)?);
57 }
58 Ok(ok.into_iter())
59 }
60}
61
62/// Trait providing try map (option) extensions to Iterators.
63///
64/// See [`TryMapAllOption::try_map_all_opt`].
65///
66/// Once `Try` (#42327) is stabilized, hopefully the `Result` and `Option` variants can be merged and generalized.
67pub trait TryMapAllOption {
68 type Item;
69 /// Applies a closure on all items of the iterator until one fails (or all succeed).
70 ///
71 /// This is [`TryMapAll::try_map_all`] - `Option` edition.
72 ///
73 /// # Arguments
74 ///
75 /// - `f`: fallible mapping function
76 ///
77 /// # Returns
78 ///
79 /// The iterator of all successes, or the first failure.
80 ///
81 /// # Examples
82 ///
83 /// Useful for propagating failures from within closures with `?` operator:
84 /// ```rust
85 /// # use crate::try_all::*;
86 /// fn not_zero(is: Vec<u64>) -> Option<Vec<u64>> {
87 /// Some(is.into_iter().try_map_all_opt(|i| if i > 0 { Some(i) } else { None })?.collect())
88 /// }
89 /// ```
90 ///
91 /// Due to the nature of operation, the function has to collect intermediate results.
92 /// In other words, if `f` has side effects, expect them for all applications until \[including\] first failure.
93 /// Additionally, this won't work on infinite sequences :o.
94 fn try_map_all_opt<T>(self, f: impl Fn(Self::Item) -> Option<T>) -> Option<Recollector<T>>;
95}
96
97impl<I: Iterator> TryMapAllOption for I {
98 type Item = I::Item;
99 fn try_map_all_opt<T>(self, f: impl Fn(Self::Item) -> Option<T>) -> Option<Recollector<T>> {
100 let mut ok = Vec::new();
101 for t in self {
102 ok.push(f(t)?);
103 }
104 Some(ok.into_iter())
105 }
106}
107
108#[cfg(test)]
109mod test {
110 use super::*;
111 #[test]
112 fn test_try_map_all(){
113 assert_eq!(vec![Ok(0), Ok(1), Ok(2), Err("no u!")].into_iter().take(3).try_map_all(|i| i).map(|v| v.collect()), Ok(vec![0, 1, 2]));
114 assert_eq!(vec![Ok(0), Ok(1), Err("no u!")].into_iter().try_map_all(|i| i).map(|v| v.collect::<Vec<_>>()), Err("no u!"));
115 assert_eq!(vec![Err("me is 1st"), Ok(1), Err("no u!")].into_iter().try_map_all(|i| i).map(|v| v.collect::<Vec<_>>()), Err("me is 1st"));
116 }
117 #[test]
118 fn test_try_map_all_opt(){
119 assert_eq!(vec![Some(0), Some(1), Some(2)].into_iter().try_map_all_opt(|i| i).map(|v| v.collect::<Vec<_>>()), Some(vec![0, 1, 2]));
120 assert_eq!(vec![Some(0), None, Some(2)].into_iter().try_map_all_opt(|i| i).map(|v| v.collect::<Vec<_>>()), None);
121 }
122}