1use crate::Error;
2use std::ops::Deref;
3
4pub type Result<T> = std::result::Result<T, Errors>;
5
6#[derive(Debug, PartialEq)]
7pub struct Errors(Vec<Error>);
8
9impl Deref for Errors {
10 type Target = [Error];
11
12 fn deref(&self) -> &Self::Target {
13 &self.0
14 }
15}
16
17impl From<Error> for Errors {
18 fn from(value: Error) -> Self {
19 Self(vec![value])
20 }
21}
22
23impl From<Vec<Error>> for Errors {
24 fn from(value: Vec<Error>) -> Self {
25 Self(value)
26 }
27}
28
29impl Errors {
30 pub fn empty() -> Errors {
31 Self(vec![])
32 }
33
34 pub fn combine(
35 a: impl Into<Option<Errors>>,
36 b: impl Into<Option<Errors>>,
37 ) -> Option<Errors> {
38 match (a.into(), b.into()) {
39 (None, None) => None,
40 (Some(e), None) | (None, Some(e)) => Some(e),
41 (Some(mut e1), Some(e2)) => {
42 e1.0.extend(e2.0);
43 Some(e1)
44 }
45 }
46 }
47
48 pub fn append(&mut self, errors: impl Into<Errors>) {
49 self.0.append(&mut errors.into().0);
50 }
51}
52
53pub trait CombineResults {
58 type Output;
59 fn all_ok(self) -> Result<Self::Output>;
60}
61
62impl<T, E> CombineResults for Vec<std::result::Result<T, E>>
63where
64 E: Into<Errors>,
65{
66 type Output = Vec<T>;
67
68 fn all_ok(self) -> Result<Self::Output> {
69 let mut values = Vec::with_capacity(self.len());
70 let mut errors: Option<Errors> = None;
71
72 for res in self {
73 match res {
74 Ok(v) => values.push(v),
75 Err(e) => {
76 errors = Errors::combine(errors, e.into());
77 }
78 }
79 }
80
81 if let Some(e) = errors {
82 Err(e)
83 } else {
84 Ok(values)
85 }
86 }
87}
88
89macro_rules! impl_combine_results {
90 ( $( $name:ident, $err:ident ),+ ) => {
91 impl< $( $name, $err ),+ > CombineResults for ( $( std::result::Result<$name, $err> ),+ )
92 where $( $err: Into<Errors>, )+
93 {
94 type Output = ( $( $name ),+ );
95
96 #[allow(non_snake_case)]
97 fn all_ok(self) -> Result<Self::Output> {
98 let ( $( $name ),+ ) = self;
99
100 let mut errors: Option<Errors> = None;
101
102 $(
103 let $name = match $name {
104 Ok(v) => Some(v),
105 Err(e) => {
106 errors = Errors::combine(errors, e.into());
107 None
108 }
109 };
110 )+
111
112 if let Some(e) = errors {
113 Err(e)
114 } else {
115 Ok(( $( $name.unwrap() ),+ ))
116 }
117 }
118 }
119 };
120}
121impl_combine_results!(A, EA, B, EB);
122impl_combine_results!(A, EA, B, EB, C, EC);
123impl_combine_results!(A, EA, B, EB, C, EC, D, ED);
124impl_combine_results!(A, EA, B, EB, C, EC, D, ED, E, EE);
125impl_combine_results!(A, EA, B, EB, C, EC, D, ED, E, EE, F, EF);