1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
extern crate proc_macro; mod arguments; mod options; use proc_macro::TokenStream; #[proc_macro_derive(Arguments, attributes(description))] pub fn args_derive(input: TokenStream) -> TokenStream { let ast = syn::parse(input).unwrap(); arguments::impl_arguments(&ast) } #[proc_macro_derive(Options, attributes(description, short))] pub fn options_derive(input: TokenStream) -> TokenStream { let ast = syn::parse(input).unwrap(); options::impl_options(&ast) } fn extract_name_values(attrs: &[syn::Attribute]) -> Vec<syn::MetaNameValue> { attrs .iter() .filter_map(syn::Attribute::interpret_meta) .filter_map(|meta| { if let syn::Meta::NameValue(name_value) = meta { Some(name_value) } else { None } }) .collect() } fn get_single_attribute<'a>( name: &'static str, attrs: &'a [syn::MetaNameValue], ) -> Option<&'a syn::Lit> { let extracted: Vec<_> = attrs .iter() .filter(|attr| attr.ident == name) .map(|attr| &attr.lit) .collect(); if extracted.len() > 1 { panic!(format!("Invalid duplicated attribute `{}`", name)); } extracted.into_iter().next() } fn get_description(name_values: &[syn::MetaNameValue]) -> String { if let Some(lit) = get_single_attribute("description", name_values) { if let syn::Lit::Str(string) = lit { string.value() } else { panic!("Invalid usage of the `description` attribute"); } } else { String::new() } }