use darling::FromVariant;
use proc_macro2::TokenStream;
use quote::quote;
use syn::{Data, DeriveInput};
#[derive(Default, FromVariant)]
#[darling(attributes(action), default)]
struct StageAttrs {
stage: Option<u32>,
}
macro_rules! match_arms {
( $x:ident, $input:expr ) => {
match $input.data {
Data::Enum(ref data) => data
.variants
.iter()
.flat_map(|variant| m::$x(&$input.ident, variant))
.collect(),
_ => panic!("unsupported data structure"),
};
};
}
mod m {
use super::StageAttrs;
use darling::FromVariant;
use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::{Fields, Ident, Token, Variant};
pub fn name(name: &Ident, variant: &Variant) -> TokenStream {
let ident = &variant.ident;
let ident_s = ident.to_string();
match &variant.fields {
Fields::Unit => {
quote! {
#name::#ident => #ident_s,
}
}
Fields::Unnamed(fields) => {
let bindings = vec); fields.unnamed.len()];
quote! {
#name::#ident(#(#bindings),*) => #ident_s,
}
}
Fields::Named(_) => {
quote! {
#name::#ident { .. } => #ident_s,
}
}
}
}
pub fn stage(name: &Ident, variant: &Variant) -> TokenStream {
let stage = StageAttrs::from_variant(&variant)
.expect("failed to parse stage attributes")
.stage
.unwrap_or(0);
let ident = &variant.ident;
match &variant.fields {
Fields::Unit => {
quote! {
#name::#ident => #stage,
}
}
Fields::Unnamed(fields) => {
let bindings = vec); fields.unnamed.len()];
quote! {
#name::#ident(#(#bindings),*) => #stage,
}
}
Fields::Named(_) => {
quote! {
#name::#ident { .. } => #stage,
}
}
}
}
}
pub fn derive(input: DeriveInput) -> TokenStream {
let name = &input.ident;
let name_body: TokenStream = match_arms!(name, input);
let stage_body: TokenStream = match_arms!(stage, input);
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
quote! {
impl#impl_generics ::bk2d::Action for #name#ty_generics #where_clause {
fn name(&self) -> &'static str {
match self {
#name_body
}
}
fn stage(&self) -> u32 {
match self {
#stage_body
}
}
}
}
}