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