13
13
use std:: env;
14
14
use std:: io:: Write ;
15
15
use std:: process:: { Command , Stdio } ;
16
+ use thiserror:: Error ;
16
17
17
18
/// Describes the style to pass to clang-format
18
19
///
@@ -86,18 +87,17 @@ impl ClangFormatStyle {
86
87
}
87
88
88
89
/// Describes which error spawning clang-format failed with
89
- #[ derive( Debug ) ]
90
- pub enum ClangFormatError {
91
- /// Failed to spawn the clang-format process
92
- SpawnFailure ,
93
- /// Failed to retrieve the stdin handle
94
- StdInFailure ,
95
- /// Failed to write the input to the stdin handle
96
- StdInWriteFailure ,
97
- /// Failed to convert the clang-format stdout to UTF-8
98
- Utf8FormatError ,
99
- /// Failed to wait for the process to end with output
100
- WaitFailure ,
90
+ #[ derive( Error , Debug ) ]
91
+ enum ClangFormatError {
92
+ #[ error( transparent) ]
93
+ Io ( #[ from] std:: io:: Error ) ,
94
+ #[ error( transparent) ]
95
+ FromUtf8Error ( #[ from] std:: string:: FromUtf8Error ) ,
96
+ // TODO: use ExitStatusError once it is a stable feature
97
+ // https://doc.rust-lang.org/stable/std/process/struct.ExitStatusError.html
98
+ // https://github.com/rust-lang/rust/issues/84908
99
+ #[ error( "Clang format process exited with a non-zero status" ) ]
100
+ NonZeroExitStatus ,
101
101
}
102
102
103
103
/// Execute clang-format with the given input, using the given style, and collect the output
@@ -120,43 +120,32 @@ pub enum ClangFormatError {
120
120
pub fn clang_format_with_style (
121
121
input : & str ,
122
122
style : & ClangFormatStyle ,
123
- ) -> Result < String , ClangFormatError > {
123
+ ) -> Result < String , impl std :: error :: Error > {
124
124
// Create and try to spawn the command with the specified style
125
125
let clang_binary = env:: var ( "CLANG_FORMAT_BINARY" ) . unwrap_or ( "clang-format" . to_string ( ) ) ;
126
- if let Ok ( mut child) = Command :: new ( clang_binary. as_str ( ) )
126
+ let mut child = Command :: new ( clang_binary. as_str ( ) )
127
127
. arg ( format ! ( "--style={}" , style. as_str( ) ) )
128
128
. stdin ( Stdio :: piped ( ) )
129
129
. stdout ( Stdio :: piped ( ) )
130
- . spawn ( )
130
+ . spawn ( ) ?;
131
+
132
+ // Write the input to stdin
133
+ //
134
+ // Note we place inside a scope to ensure that stdin is closed
131
135
{
132
- // Try to take the stdin pipe
133
- if let Some ( mut stdin) = child. stdin . take ( ) {
134
- // Write the input to the stdin
135
- if write ! ( stdin, "{}" , input) . is_err ( ) {
136
- return Err ( ClangFormatError :: StdInWriteFailure ) ;
137
- }
138
- } else {
139
- return Err ( ClangFormatError :: StdInFailure ) ;
140
- }
136
+ let mut stdin = child. stdin . take ( ) . expect ( "no stdin handle" ) ;
137
+ write ! ( stdin, "{}" , input) ?;
138
+ }
141
139
142
- // Wait for the output
143
- //
144
- // Note this cannot be inside the stdin block, as stdin is only closed
145
- // when it goes out of scope
146
- if let Ok ( output) = child. wait_with_output ( ) {
147
- // Parse the output into a String
148
- //
149
- // TODO: do we need to check stderr or exitcode?
150
- if let Ok ( stdout) = String :: from_utf8 ( output. stdout ) {
151
- Ok ( stdout)
152
- } else {
153
- Err ( ClangFormatError :: Utf8FormatError )
154
- }
155
- } else {
156
- Err ( ClangFormatError :: WaitFailure )
157
- }
140
+ // Wait for the output and parse it
141
+ let output = child. wait_with_output ( ) ?;
142
+ // TODO: use exit_ok() once it is a stable feature
143
+ // https://doc.rust-lang.org/stable/std/process/struct.ExitStatus.html#method.exit_ok
144
+ // https://github.com/rust-lang/rust/issues/84908
145
+ if output. status . success ( ) {
146
+ Ok ( String :: from_utf8 ( output. stdout ) ?)
158
147
} else {
159
- Err ( ClangFormatError :: SpawnFailure )
148
+ Err ( ClangFormatError :: NonZeroExitStatus )
160
149
}
161
150
}
162
151
@@ -179,7 +168,7 @@ pub fn clang_format_with_style(
179
168
/// assert_eq!(output.unwrap(), "\nstruct Test {};\n");
180
169
/// # }
181
170
/// ```
182
- pub fn clang_format ( input : & str ) -> Result < String , ClangFormatError > {
171
+ pub fn clang_format ( input : & str ) -> Result < String , impl std :: error :: Error > {
183
172
clang_format_with_style ( input, & ClangFormatStyle :: Default )
184
173
}
185
174
0 commit comments