Fallible Settings (#42938)
Also tidies up error notifications so that in the case of syntax errors we don't see noise about the migration failing as well. Release Notes: - Invalid values in settings files will no longer prevent the rest of the file from being parsed.
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
use proc_macro::TokenStream;
|
||||
|
||||
use quote::quote;
|
||||
use syn::{Data, DeriveInput, Fields, parse_macro_input};
|
||||
use syn::{
|
||||
Data, DeriveInput, Field, Fields, ItemEnum, ItemStruct, Type, parse_macro_input, parse_quote,
|
||||
};
|
||||
|
||||
/// Derives the `MergeFrom` trait for a struct.
|
||||
///
|
||||
@@ -100,3 +103,50 @@ pub fn derive_register_setting(input: TokenStream) -> TokenStream {
|
||||
}
|
||||
.into()
|
||||
}
|
||||
|
||||
// Adds serde attributes to each field with type Option<T>:
|
||||
// #serde(default, skip_serializing_if = "Option::is_none", deserialize_with = "settings::deserialize_fallible")
|
||||
#[proc_macro_attribute]
|
||||
pub fn with_fallible_options(_args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
fn apply_on_fields(fields: &mut Fields) {
|
||||
match fields {
|
||||
Fields::Unit => {}
|
||||
Fields::Named(fields) => {
|
||||
for field in &mut fields.named {
|
||||
add_if_option(field)
|
||||
}
|
||||
}
|
||||
Fields::Unnamed(fields) => {
|
||||
for field in &mut fields.unnamed {
|
||||
add_if_option(field)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn add_if_option(field: &mut Field) {
|
||||
match &field.ty {
|
||||
Type::Path(syn::TypePath { qself: None, path })
|
||||
if path.leading_colon.is_none()
|
||||
&& path.segments.len() == 1
|
||||
&& path.segments[0].ident == "Option" => {}
|
||||
_ => return,
|
||||
}
|
||||
let attr = parse_quote!(
|
||||
#[serde(default, skip_serializing_if = "Option::is_none", deserialize_with="crate::fallible_options::deserialize")]
|
||||
);
|
||||
field.attrs.push(attr);
|
||||
}
|
||||
|
||||
if let Ok(mut input) = syn::parse::<ItemStruct>(input.clone()) {
|
||||
apply_on_fields(&mut input.fields);
|
||||
quote!(#input).into()
|
||||
} else if let Ok(mut input) = syn::parse::<ItemEnum>(input) {
|
||||
for variant in &mut input.variants {
|
||||
apply_on_fields(&mut variant.fields);
|
||||
}
|
||||
quote!(#input).into()
|
||||
} else {
|
||||
panic!("with_fallible_options can only be applied to struct or enum definitions.");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user