use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput};
#[proc_macro_derive(UID, attributes(uid, alias))]
pub fn derive(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
Parser::new(&input)
.map_or_else(syn::Error::into_compile_error, |parser| {
if let Some(alias_attrs) = parser.alias_attrs {
let aliases: Vec<_> = alias_attrs
.iter()
.map(|alias| alias.expand(&input))
.collect();
quote!(#(#aliases)*)
} else {
parser.uid_attrs.expand(&input)
}
})
.into()
}
mod alias;
mod uid;
#[derive(Debug, Clone, Default)]
struct Parser {
pub uid_attrs: uid::Attributes,
pub alias_attrs: Option<Vec<alias::Attributes>>,
}
impl Parser {
fn new(input: &DeriveInput) -> syn::Result<Parser> {
let mut parser: Parser = Default::default();
for attr in &input.attrs {
if attr.path().is_ident("uid") {
parser.uid_attrs = attr.parse_args()?;
}
if attr.path().is_ident("alias") {
parser
.alias_attrs
.get_or_insert(vec![])
.push(attr.parse_args()?);
}
}
parser
.alias_attrs
.iter_mut()
.flatten()
.skip(1)
.for_each(|alias| {
alias.skip_uid = true;
});
Ok(parser)
}
}
type Expanded = proc_macro2::TokenStream;
trait Expand {
fn expand(&self, input: &DeriveInput) -> Expanded;
}