use darling::{ast::Data, FromDeriveInput, FromField};
use proc_macro2::TokenStream;
use quote::{quote, ToTokens};
use syn::{Generics, Ident};
#[derive(FromDeriveInput)]
#[darling(attributes(field_name), supports(struct_named))]
pub(crate) struct Receiver {
ident: Ident,
generics: Generics,
data: Data<(), ReceiverField>,
}
#[derive(FromField)]
#[darling(attributes(field_name))]
struct ReceiverField {
ident: Option<Ident>,
#[darling(default)]
rename: Option<String>,
#[darling(default)]
skip: bool,
}
impl ToTokens for Receiver {
fn to_tokens(&self, tokens: &mut TokenStream) {
let ident = &self.ident;
let (impl_generics, ty_generics, where_clause) = self.generics.split_for_impl();
let fields = self.data
.as_ref()
.take_struct()
.expect("FieldNames only supports named structs")
.into_iter()
.filter(|f| !f.skip)
.collect::<Vec<_>>();
let field_values: Vec<String> = fields.iter()
.map(|f| f.rename.clone().unwrap_or_else(|| f.ident.as_ref().unwrap().to_string()))
.collect();
let individual_consts = fields.iter().map(|f| {
let field_ident = f.ident.as_ref().unwrap();
let const_name = Ident::new(
&field_ident.to_string().to_uppercase(),
field_ident.span()
);
let const_value = f.rename.clone().unwrap_or_else(|| field_ident.to_string());
quote! {
pub const #const_name: &'static str = #const_value;
}
});
let fields_len = field_values.len();
tokens.extend(quote! {
#[automatically_derived]
impl #impl_generics #ident #ty_generics #where_clause {
pub const FIELDS: [&'static str; #fields_len] = [
#(#field_values),*
];
#(#individual_consts)*
}
});
}
}