|
| 1 | +/// If at least one `Result` is an error, turn all of them into errors. Else, unwrap the `Result`s. |
| 2 | +/// |
| 3 | +/// See [fail_all_vec] for an easier-to-understand version specialized for `Vec`. |
| 4 | +/// |
| 5 | +/// [fail_all] is its lower-level implementation. You probably want to create |
| 6 | +/// a similar wrapper function instead of using [fail_all] directly. |
| 7 | +/// |
| 8 | +/// ## Examples |
| 9 | +/// |
| 10 | +/// ```rust |
| 11 | +/// # use multiple_errors::fail_all; |
| 12 | +/// # use multiple_errors::testing_prelude::*; |
| 13 | +/// # |
| 14 | +/// // Manually: |
| 15 | +/// |
| 16 | +/// let Ok(ok) = fail_all([Ok(A), Ok(A)], |_: Result<_, ErrA>| ErrC) else { |
| 17 | +/// panic!(); |
| 18 | +/// }; |
| 19 | +/// assert_eq!(ok.collect::<Vec<_>>(), vec![A, A]); |
| 20 | +/// |
| 21 | +/// // Or using a helper function for your container: |
| 22 | +/// |
| 23 | +/// pub fn fail_all_3<T, E1, E2, F>(results: [Result<T, E1>; 3], f: F) -> Result<[T; 3], [E2; 3]> |
| 24 | +/// where |
| 25 | +/// F: FnMut(Result<T, E1>) -> E2, |
| 26 | +/// { |
| 27 | +/// fn collect_3<T>(mut iter: impl Iterator<Item = T>) -> [T; 3] { |
| 28 | +/// core::array::from_fn(|_| iter.next().expect("the iterator should have 3 elements")) |
| 29 | +/// } |
| 30 | +/// fail_all(results, f).map(collect_3).map_err(collect_3) |
| 31 | +/// } |
| 32 | +/// |
| 33 | +/// let err = fail_all_3( |
| 34 | +/// [Ok(A), Err(ErrA), Ok(A)], |
| 35 | +/// |res| res.err().map(HighLevelErr::from).unwrap_or(HighLevelErr::B(ErrB)) |
| 36 | +/// ); |
| 37 | +/// assert_eq!(err, Err([ErrB.into(), ErrA.into(), ErrB.into()])); |
| 38 | +/// ``` |
| 39 | +pub fn fail_all<I, T, E1, E2, F>( |
| 40 | + results: I, |
| 41 | + f: F, |
| 42 | +) -> Result<impl Iterator<Item = T>, impl Iterator<Item = E2>> |
| 43 | +where |
| 44 | + I: IntoIterator<Item = Result<T, E1>>, |
| 45 | + for<'a> &'a I: IntoIterator<Item = &'a Result<T, E1>>, |
| 46 | + F: FnMut(Result<T, E1>) -> E2, |
| 47 | +{ |
| 48 | + if (&results).into_iter().any(Result::is_err) { |
| 49 | + return Err(results.into_iter().map(f)); |
| 50 | + } |
| 51 | + Ok(results.into_iter().map( |
| 52 | + // This was going to be an `expect()`, but it requires an easily avoidable `E1: Debug`. |
| 53 | + |res| { |
| 54 | + res.ok() |
| 55 | + .unwrap_or_else(|| panic!("errors should be handled in the previous branch")) |
| 56 | + }, |
| 57 | + )) |
| 58 | +} |
| 59 | + |
| 60 | +/// If at least one `Result` is an error, turn all of them into errors. Else, unwrap the `Result`s. |
| 61 | +/// |
| 62 | +/// See [fail_all] for a more generic/low-level version that works with other |
| 63 | +/// input containers and doesn't `collect()`. |
| 64 | +/// |
| 65 | +/// ## Examples |
| 66 | +/// |
| 67 | +/// ```rust |
| 68 | +/// # use multiple_errors::fail_all_vec; |
| 69 | +/// # use multiple_errors::testing_prelude::*; |
| 70 | +/// # |
| 71 | +/// let err = fail_all_vec( |
| 72 | +/// vec![Ok(A), Err(ErrA), Ok(A)], |
| 73 | +/// |res| res.err().map(HighLevelErr::from).unwrap_or(HighLevelErr::B(ErrB)) |
| 74 | +/// ); |
| 75 | +/// assert_eq!(err, Err(vec![ErrB.into(), ErrA.into(), ErrB.into()])); |
| 76 | +/// |
| 77 | +/// let ok = fail_all_vec(vec![Ok(A), Ok(A)], |_: Result<_, ErrA>| ErrC); |
| 78 | +/// assert_eq!(ok, Ok(vec![A, A])); |
| 79 | +/// ``` |
| 80 | +pub fn fail_all_vec<T, E1, E2, F>(results: Vec<Result<T, E1>>, f: F) -> Result<Vec<T>, Vec<E2>> |
| 81 | +where |
| 82 | + F: FnMut(Result<T, E1>) -> E2, |
| 83 | +{ |
| 84 | + fail_all(results, f) |
| 85 | + .map(Iterator::collect) |
| 86 | + .map_err(Iterator::collect) |
| 87 | +} |
0 commit comments