@@ -212,41 +212,52 @@ macro_rules! define_Conf {
212
212
fn visit_map<V >( self , mut map: V ) -> Result <Self :: Value , V :: Error > where V : MapAccess <' de> {
213
213
let mut errors = Vec :: new( ) ;
214
214
let mut warnings = Vec :: new( ) ;
215
+
216
+ // Declare a local variable for each field in the configuration file.
215
217
$( let mut $name = None ; ) *
218
+
216
219
// could get `Field` here directly, but get `String` first for diagnostics
217
220
while let Some ( name) = map. next_key:: <toml:: Spanned <String >>( ) ? {
218
- match Field :: deserialize( name. get_ref( ) . as_str( ) . into_deserializer( ) ) {
221
+ let field = match Field :: deserialize( name. get_ref( ) . as_str( ) . into_deserializer( ) ) {
219
222
Err ( e) => {
220
223
let e: FieldError = e;
221
224
errors. push( ConfError :: spanned( self . 0 , e. error, e. suggestion, name. span( ) ) ) ;
225
+ continue ;
222
226
}
223
- $( Ok ( Field :: $name) => {
227
+ Ok ( field) => field
228
+ } ;
229
+
230
+ match field {
231
+ $( Field :: $name => {
232
+ // Is this a deprecated field, i.e., is `$dep` set? If so, push a warning.
224
233
$( warnings. push( ConfError :: spanned( self . 0 , format!( "deprecated field `{}`. {}" , name. get_ref( ) , $dep) , None , name. span( ) ) ) ; ) ?
225
234
let raw_value = map. next_value:: <toml:: Spanned <toml:: Value >>( ) ?;
226
235
let value_span = raw_value. span( ) ;
227
- match <$ty>:: deserialize( raw_value. into_inner( ) ) {
228
- Err ( e) => errors. push( ConfError :: spanned( self . 0 , e. to_string( ) . replace( '\n' , " " ) . trim( ) , None , value_span) ) ,
229
- Ok ( value) => match $name {
230
- Some ( _) => {
231
- errors. push( ConfError :: spanned( self . 0 , format!( "duplicate field `{}`" , name. get_ref( ) ) , None , name. span( ) ) ) ;
232
- }
233
- None => {
234
- $name = Some ( value) ;
235
- // $new_conf is the same as one of the defined `$name`s, so
236
- // this variable is defined in line 2 of this function.
237
- $( match $new_conf {
238
- Some ( _) => errors. push( ConfError :: spanned( self . 0 , concat!(
239
- "duplicate field `" , stringify!( $new_conf) ,
240
- "` (provided as `" , stringify!( $name) , "`)"
241
- ) , None , name. span( ) ) ) ,
242
- None => $new_conf = $name. clone( ) ,
243
- } ) ?
244
- } ,
236
+ let value = match <$ty>:: deserialize( raw_value. into_inner( ) ) {
237
+ Err ( e) => {
238
+ errors. push( ConfError :: spanned( self . 0 , e. to_string( ) . replace( '\n' , " " ) . trim( ) , None , value_span) ) ;
239
+ continue ;
245
240
}
241
+ Ok ( value) => value
242
+ } ;
243
+ // Was this field set previously?
244
+ if $name. is_some( ) {
245
+ errors. push( ConfError :: spanned( self . 0 , format!( "duplicate field `{}`" , name. get_ref( ) ) , None , name. span( ) ) ) ;
246
+ continue ;
246
247
}
248
+ $name = Some ( value) ;
249
+ // If this is a deprecated field, was the new field (`$new_conf`) set previously?
250
+ // Note that `$new_conf` is one of the defined `$name`s.
251
+ $( match $new_conf {
252
+ Some ( _) => errors. push( ConfError :: spanned( self . 0 , concat!(
253
+ "duplicate field `" , stringify!( $new_conf) ,
254
+ "` (provided as `" , stringify!( $name) , "`)"
255
+ ) , None , name. span( ) ) ) ,
256
+ None => $new_conf = $name. clone( ) ,
257
+ } ) ?
247
258
} ) *
248
259
// ignore contents of the third_party key
249
- Ok ( Field :: third_party) => drop( map. next_value:: <IgnoredAny >( ) )
260
+ Field :: third_party => drop( map. next_value:: <IgnoredAny >( ) )
250
261
}
251
262
}
252
263
let conf = Conf { $( $name: $name. unwrap_or_else( defaults:: $name) , ) * } ;
0 commit comments