use crate::proc_macro::TokenStream;
use std::collections::HashMap;
use syn::{Lit, Meta, MetaNameValue, MetaList};
pub fn derive_macro<F>(tokens: TokenStream, gen_impl: F) -> TokenStream
where F: Fn(&syn::Ident, Vec<String>, HashMap<String, Vec<String>>) -> TokenStream {
let ast: syn::ItemEnum = syn::parse(tokens).unwrap();
let mut attributes: HashMap<String, Vec<String>> = HashMap::new();
let mut variants: Vec<String> = Vec::new();
for variant in ast.variants.iter() {
let variant = variant.ident.to_string();
variants.push(variant);
}
for attr in ast.attrs.into_iter() {
let option = attr.parse_meta().unwrap();
match option {
Meta::List(MetaList{ref path, ref nested, ..}) => {
let segment = path.segments.first().unwrap();
let ident = segment.ident.clone();
let mut values: Vec<String> = Vec::new();
if attributes.get(ident.to_string().as_str()).is_some() {
values.extend(attributes.get(ident.to_string().as_str()).unwrap().iter().cloned());
}
for nested_meta in nested.iter() {
match nested_meta {
syn::NestedMeta::Meta(meta) => {
match meta {
Meta::Path(path) => {
let segment = path.segments.first().unwrap();
let ident = segment.ident.clone();
values.push(ident.to_string());
()
},
_=> ()
}
},
_ => ()
}
}
attributes.insert(ident.to_string(), values);
()
},
Meta::NameValue(MetaNameValue{ref path, ref lit, ..}) => {
let segment = path.segments.first().unwrap();
let ident = segment.ident.clone();
if let Lit::Str(lit) = lit {
let mut values: Vec<String> = Vec::new();
if attributes.get(ident.to_string().as_str()).is_some() {
values.extend(attributes.get(ident.to_string().as_str()).unwrap().iter().cloned());
}
values.push(lit.value());
attributes.insert(ident.to_string(), values);
}
},
_=> ()
}
}
gen_impl(&ast.ident, variants, attributes)
}