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}