1
1
use std:: ffi;
2
2
use std:: fmt;
3
- use std:: result ;
3
+ use std:: io ;
4
4
5
5
use failure;
6
6
7
- pub type Result < T > = result:: Result < T , failure:: Error > ;
8
-
9
7
fn format_cmd ( cmd : & [ ffi:: OsString ] ) -> String {
10
8
let result: Vec < String > = cmd. iter ( )
11
9
. map ( |s| s. to_string_lossy ( ) . into_owned ( ) )
12
10
. collect ( ) ;
13
11
result. join ( " " )
14
12
}
15
13
16
- #[ derive( Fail , Debug ) ]
17
- pub struct SpawnError {
18
- cmd : Vec < ffi:: OsString > ,
14
+ pub trait ChainFail {
15
+ fn chain < E > ( self , cause : E ) -> Self
16
+ where
17
+ E : Into < failure:: Error > ;
18
+ }
19
+
20
+ pub trait ResultChainExt < T > {
21
+ fn chain < C > ( self , chainable : C ) -> Result < T , C >
22
+ where
23
+ C : ChainFail ;
24
+
25
+ fn chain_with < F , C > ( self , chainable : F ) -> Result < T , C >
26
+ where
27
+ F : FnOnce ( ) -> C ,
28
+ C : ChainFail ;
19
29
}
20
30
21
- impl SpawnError {
22
- pub fn new ( cmd : Vec < ffi:: OsString > ) -> Self {
23
- Self { cmd }
31
+ impl < T > ResultChainExt < T > for Result < T , failure:: Error > {
32
+ fn chain < C > ( self , chainable : C ) -> Result < T , C >
33
+ where
34
+ C : ChainFail ,
35
+ {
36
+ self . map_err ( |e| chainable. chain ( e) )
37
+ }
38
+
39
+ fn chain_with < F , C > ( self , chainable : F ) -> Result < T , C >
40
+ where
41
+ F : FnOnce ( ) -> C ,
42
+ C : ChainFail ,
43
+ {
44
+ self . map_err ( |e| chainable ( ) . chain ( e) )
24
45
}
25
46
}
26
47
27
- impl fmt:: Display for SpawnError {
28
- fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
29
- write ! ( f, "Failed to run `{}`" , format_cmd( & self . cmd) )
48
+ impl < T > ResultChainExt < T > for Result < T , io:: Error > {
49
+ fn chain < C > ( self , chainable : C ) -> Result < T , C >
50
+ where
51
+ C : ChainFail ,
52
+ {
53
+ self . map_err ( |e| chainable. chain ( e) )
54
+ }
55
+
56
+ fn chain_with < F , C > ( self , chainable : F ) -> Result < T , C >
57
+ where
58
+ F : FnOnce ( ) -> C ,
59
+ C : ChainFail ,
60
+ {
61
+ self . map_err ( |e| chainable ( ) . chain ( e) )
30
62
}
31
63
}
32
64
33
- #[ derive( Fail , Debug ) ]
65
+ /// Failure when processing assertions.
66
+ #[ derive( Debug ) ]
34
67
pub struct AssertionError {
35
68
cmd : Vec < ffi:: OsString > ,
69
+ cause : Option < failure:: Error > ,
36
70
}
37
71
38
72
impl AssertionError {
39
- pub fn new ( cmd : Vec < ffi:: OsString > ) -> Self {
40
- Self { cmd }
73
+ pub ( crate ) fn new ( cmd : Vec < ffi:: OsString > ) -> Self {
74
+ Self { cmd, cause : None }
75
+ }
76
+ }
77
+
78
+ impl failure:: Fail for AssertionError {
79
+ fn cause ( & self ) -> Option < & failure:: Fail > {
80
+ self . cause . as_ref ( ) . map ( failure:: Error :: cause)
81
+ }
82
+
83
+ fn backtrace ( & self ) -> Option < & failure:: Backtrace > {
84
+ None
85
+ }
86
+ }
87
+
88
+ impl ChainFail for AssertionError {
89
+ fn chain < E > ( mut self , error : E ) -> Self
90
+ where
91
+ E : Into < failure:: Error > ,
92
+ {
93
+ self . cause = Some ( error. into ( ) ) ;
94
+ self
41
95
}
42
96
}
43
97
@@ -47,11 +101,12 @@ impl fmt::Display for AssertionError {
47
101
}
48
102
}
49
103
50
- #[ derive( Fail , Debug ) ]
104
+ #[ derive( Debug ) ]
51
105
pub struct StatusError {
52
106
unexpected : bool ,
53
107
stdout : Vec < u8 > ,
54
108
stderr : Vec < u8 > ,
109
+ cause : Option < failure:: Error > ,
55
110
}
56
111
57
112
impl StatusError {
@@ -60,17 +115,38 @@ impl StatusError {
60
115
unexpected,
61
116
stdout,
62
117
stderr,
118
+ cause : None ,
63
119
}
64
120
}
65
121
}
66
122
123
+ impl failure:: Fail for StatusError {
124
+ fn cause ( & self ) -> Option < & failure:: Fail > {
125
+ self . cause . as_ref ( ) . map ( failure:: Error :: cause)
126
+ }
127
+
128
+ fn backtrace ( & self ) -> Option < & failure:: Backtrace > {
129
+ None
130
+ }
131
+ }
132
+
133
+ impl ChainFail for StatusError {
134
+ fn chain < E > ( mut self , error : E ) -> Self
135
+ where
136
+ E : Into < failure:: Error > ,
137
+ {
138
+ self . cause = Some ( error. into ( ) ) ;
139
+ self
140
+ }
141
+ }
142
+
67
143
impl fmt:: Display for StatusError {
68
144
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
69
145
let out = String :: from_utf8_lossy ( & self . stdout ) ;
70
146
let err = String :: from_utf8_lossy ( & self . stderr ) ;
71
147
writeln ! (
72
148
f,
73
- "Unexpected {} return status" ,
149
+ "Unexpected return status: {} " ,
74
150
if self . unexpected {
75
151
"success"
76
152
} else {
@@ -82,12 +158,13 @@ impl fmt::Display for StatusError {
82
158
}
83
159
}
84
160
85
- #[ derive( Fail , Debug ) ]
161
+ #[ derive( Debug ) ]
86
162
pub struct ExitCodeError {
87
163
expected : Option < i32 > ,
88
164
got : Option < i32 > ,
89
165
stdout : Vec < u8 > ,
90
166
stderr : Vec < u8 > ,
167
+ cause : Option < failure:: Error > ,
91
168
}
92
169
93
170
impl ExitCodeError {
@@ -97,10 +174,31 @@ impl ExitCodeError {
97
174
got,
98
175
stdout,
99
176
stderr,
177
+ cause : None ,
100
178
}
101
179
}
102
180
}
103
181
182
+ impl failure:: Fail for ExitCodeError {
183
+ fn cause ( & self ) -> Option < & failure:: Fail > {
184
+ self . cause . as_ref ( ) . map ( failure:: Error :: cause)
185
+ }
186
+
187
+ fn backtrace ( & self ) -> Option < & failure:: Backtrace > {
188
+ None
189
+ }
190
+ }
191
+
192
+ impl ChainFail for ExitCodeError {
193
+ fn chain < E > ( mut self , error : E ) -> Self
194
+ where
195
+ E : Into < failure:: Error > ,
196
+ {
197
+ self . cause = Some ( error. into ( ) ) ;
198
+ self
199
+ }
200
+ }
201
+
104
202
impl fmt:: Display for ExitCodeError {
105
203
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
106
204
let out = String :: from_utf8_lossy ( & self . stdout ) ;
0 commit comments