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