@@ -6,6 +6,7 @@ use std::fs::File;
6
6
use std:: io:: Write ;
7
7
use std:: path:: { Path , PathBuf } ;
8
8
use std:: process:: { Command , Stdio } ;
9
+ use std:: string:: FromUtf8Error ;
9
10
10
11
use log:: debug;
11
12
use rand:: { distributions, thread_rng, Rng } ;
@@ -15,26 +16,54 @@ use serde_json;
15
16
/// Specifies which `rustfmt` to use.
16
17
#[ derive( Clone ) ]
17
18
pub enum Rustfmt {
18
- /// `(path to external `rustfmt`, current working directory to spawn at)`
19
- External ( PathBuf , PathBuf ) ,
19
+ /// Externally invoked `rustfmt` process.
20
+ External { path : PathBuf , cwd : PathBuf } ,
20
21
/// Statically linked `rustfmt`.
21
22
Internal ,
22
23
}
23
24
25
+ /// Defines a formatting-related error.
26
+ #[ derive( Fail , Debug ) ]
27
+ pub enum Error {
28
+ /// Generic variant of `Error::Rustfmt` error.
29
+ #[ fail( display = "Formatting could not be completed." ) ]
30
+ Failed ,
31
+ #[ fail( display = "Could not format source code: {}" , _0) ]
32
+ Rustfmt ( rustfmt_nightly:: ErrorKind ) ,
33
+ #[ fail( display = "Encountered I/O error: {}" , _0) ]
34
+ Io ( std:: io:: Error ) ,
35
+ #[ fail( display = "Config couldn't be converted to TOML for Rustfmt purposes: {}" , _0) ]
36
+ ConfigTomlOutput ( String ) ,
37
+ #[ fail( display = "Formatted output is not valid UTF-8 source: {}" , _0) ]
38
+ OutputNotUtf8 ( FromUtf8Error ) ,
39
+ }
40
+
41
+ impl From < std:: io:: Error > for Error {
42
+ fn from ( err : std:: io:: Error ) -> Error {
43
+ Error :: Io ( err)
44
+ }
45
+ }
46
+
47
+ impl From < FromUtf8Error > for Error {
48
+ fn from ( err : FromUtf8Error ) -> Error {
49
+ Error :: OutputNotUtf8 ( err)
50
+ }
51
+ }
52
+
24
53
impl From < Option < ( String , PathBuf ) > > for Rustfmt {
25
54
fn from ( value : Option < ( String , PathBuf ) > ) -> Rustfmt {
26
55
match value {
27
- Some ( ( path, cwd) ) => Rustfmt :: External ( PathBuf :: from ( path) , cwd) ,
56
+ Some ( ( path, cwd) ) => Rustfmt :: External { path : PathBuf :: from ( path) , cwd } ,
28
57
None => Rustfmt :: Internal ,
29
58
}
30
59
}
31
60
}
32
61
33
62
impl Rustfmt {
34
- pub fn format ( & self , input : String , cfg : Config ) -> Result < String , String > {
63
+ pub fn format ( & self , input : String , cfg : Config ) -> Result < String , Error > {
35
64
match self {
36
65
Rustfmt :: Internal => format_internal ( input, cfg) ,
37
- Rustfmt :: External ( path, cwd) => format_external ( path, cwd, input, cfg) ,
66
+ Rustfmt :: External { path, cwd } => format_external ( path, cwd, input, cfg) ,
38
67
}
39
68
}
40
69
}
@@ -44,7 +73,7 @@ fn format_external(
44
73
cwd : & PathBuf ,
45
74
input : String ,
46
75
cfg : Config ,
47
- ) -> Result < String , String > {
76
+ ) -> Result < String , Error > {
48
77
let ( _file_handle, config_path) = gen_config_file ( & cfg) ?;
49
78
let args = rustfmt_args ( & cfg, & config_path) ;
50
79
@@ -54,25 +83,18 @@ fn format_external(
54
83
. stdin ( Stdio :: piped ( ) )
55
84
. stdout ( Stdio :: piped ( ) )
56
85
. spawn ( )
57
- . map_err ( |_| format ! ( "Couldn't spawn `{}`" , path . display ( ) ) ) ?;
86
+ . map_err ( Error :: Io ) ?;
58
87
59
88
{
60
- let stdin =
61
- rustfmt. stdin . as_mut ( ) . ok_or_else ( || "Failed to open rustfmt stdin" . to_string ( ) ) ?;
62
- stdin
63
- . write_all ( input. as_bytes ( ) )
64
- . map_err ( |_| "Failed to pass input to rustfmt" . to_string ( ) ) ?;
89
+ let stdin = rustfmt. stdin . as_mut ( ) . unwrap ( ) ; // Safe because stdin is piped
90
+ stdin. write_all ( input. as_bytes ( ) ) ?;
65
91
}
66
92
67
- rustfmt. wait_with_output ( ) . map_err ( |err| format ! ( "Error running rustfmt: {}" , err) ) . and_then (
68
- |out| {
69
- String :: from_utf8 ( out. stdout )
70
- . map_err ( |_| "Formatted code is not valid UTF-8" . to_string ( ) )
71
- } ,
72
- )
93
+ let output = rustfmt. wait_with_output ( ) ?;
94
+ Ok ( String :: from_utf8 ( output. stdout ) ?)
73
95
}
74
96
75
- fn format_internal ( input : String , config : Config ) -> Result < String , String > {
97
+ fn format_internal ( input : String , config : Config ) -> Result < String , Error > {
76
98
let mut buf = Vec :: < u8 > :: new ( ) ;
77
99
78
100
{
@@ -85,37 +107,34 @@ fn format_internal(input: String, config: Config) -> Result<String, String> {
85
107
if session. has_operational_errors ( ) || session. has_parsing_errors ( ) {
86
108
debug ! ( "reformat: format_input failed: has errors, report = {}" , report) ;
87
109
88
- return Err ( "Reformat failed to complete successfully" . into ( ) ) ;
110
+ return Err ( Error :: Failed ) ;
89
111
}
90
112
}
91
113
Err ( e) => {
92
114
debug ! ( "Reformat failed: {:?}" , e) ;
93
115
94
- return Err ( "Reformat failed to complete successfully" . into ( ) ) ;
116
+ return Err ( Error :: Rustfmt ( e ) ) ;
95
117
}
96
118
}
97
119
}
98
120
99
- String :: from_utf8 ( buf) . map_err ( |_| "Reformat output is not a valid UTF-8" . into ( ) )
121
+ Ok ( String :: from_utf8 ( buf) ? )
100
122
}
101
123
102
- fn random_file ( ) -> Result < ( File , PathBuf ) , String > {
124
+ fn random_file ( ) -> Result < ( File , PathBuf ) , Error > {
103
125
const SUFFIX_LEN : usize = 10 ;
104
126
105
127
let suffix: String =
106
128
thread_rng ( ) . sample_iter ( & distributions:: Alphanumeric ) . take ( SUFFIX_LEN ) . collect ( ) ;
107
129
let path = temp_dir ( ) . join ( suffix) ;
108
130
109
- Ok ( File :: create ( & path)
110
- . map ( |file| ( file, path) )
111
- . map_err ( |_| "Config file could not be created" . to_string ( ) ) ?)
131
+ Ok ( File :: create ( & path) . map ( |file| ( file, path) ) ?)
112
132
}
113
133
114
- fn gen_config_file ( config : & Config ) -> Result < ( File , PathBuf ) , String > {
134
+ fn gen_config_file ( config : & Config ) -> Result < ( File , PathBuf ) , Error > {
115
135
let ( mut file, path) = random_file ( ) ?;
116
- let toml = config. all_options ( ) . to_toml ( ) ?;
117
- file. write ( toml. as_bytes ( ) )
118
- . map_err ( |_| "Could not write config TOML file contents" . to_string ( ) ) ?;
136
+ let toml = config. all_options ( ) . to_toml ( ) . map_err ( Error :: ConfigTomlOutput ) ?;
137
+ file. write_all ( toml. as_bytes ( ) ) ?;
119
138
120
139
Ok ( ( file, path) )
121
140
}
0 commit comments