in rust/ccommon-derive/src/lib.rs [236:352]
fn derive_options_impl(input: DeriveInput) -> Result<proc_macro2::TokenStream, Error> {
let krate = crate_name("ccommon-rs")?;
let data = match input.data {
Data::Struct(data) => data,
Data::Enum(data) => {
return Err(Error::new(
data.enum_token.span(),
"Can only derive Metrics for a struct",
))
}
Data::Union(data) => {
return Err(Error::new(
data.union_token.span(),
"Can only derive Metrics for a struct",
))
}
};
if !is_repr_c_or_transparent(&input.attrs) {
return Err(Error::new(
input.ident.span(),
format!(
"`{}` must be either #[repr(C)] or #[repr(transparent)] to implement Metrics",
input.ident
),
));
}
if has_generics(&input.generics) {
return Err(Error::new(
input.generics.span(),
"Cannot derive Metrics for a struct with generics",
));
}
let ident = input.ident;
let process_field = |is_tuple| {
let krate = krate.clone();
move |(i, field): (usize, &Field)| {
let ty = &field.ty;
let name = &field.ident;
let label = if is_tuple {
quote! {}
} else {
quote! { #name: }
};
Ok(match get_option_attr(&field.attrs)? {
Some(attr) => {
let desc = to_c_str(&attr.desc.val);
let namestr = match attr.name {
Some(name) => to_c_str(&name.val),
None => match field.ident.as_ref() {
Some(name) => to_c_str(&name_as_lit(name)),
None => {
to_c_str(&Lit::Str(LitStr::new(&format!("{}", i), field.span())))
}
},
};
match attr.default.map(|x| x.val) {
Some(default) => quote! {
#label <#ty as #krate::option::SingleOption>::new(
#default,
#namestr,
#desc
)
},
None => quote! {
#label <#ty as #krate::option::SingleOption>::defaulted(#namestr, #desc)
},
}
}
None => quote! {
#label <#ty as #krate::option::Options>::new()
},
})
}
};
let initializer = match data.fields {
Fields::Named(fields) => {
let initializers: Vec<_> = fields
.named
.iter()
.enumerate()
.map(process_field(false))
.collect::<Result<_, Error>>()?;
quote! {
Self { #( #initializers, )* }
}
}
Fields::Unnamed(fields) => {
let initializers: Vec<_> = fields
.unnamed
.iter()
.enumerate()
.map(process_field(true))
.collect::<Result<_, Error>>()?;
quote! {
Self ( #( #initializers, )* )
}
}
Fields::Unit => quote!(Self),
};
Ok(quote! {
unsafe impl #krate::option::Options for #ident {
fn new() -> Self {
#initializer
}
}
})
}