use util;
pub fn derive_parse_args(input: &syn::DeriveInput) -> proc_macro2::TokenStream {
let struct_def = util::derive_input_to_struct_def(input);
let mut parser_components = quote! {};
let mut unknown_args_field: Option<util::StructField> = None;
for ref field in struct_def.fields {
if field.unknown_args {
if unknown_args_field.is_some() {
panic!("Only one unknown_args field may be defined");
}
unknown_args_field = Some(field.clone());
}
let field_ident = &field.ident;
let field_type = &field.ty;
let span = field_ident.span();
match &field.long_option {
Some(ref long_option) => {
let long_option = String::from("--") + long_option;
parser_components.extend(quote_spanned!{span=>
match <#field_type as jockey::Parsable>::parse_arg(&mut iter, &#long_option.to_string()) {
Some(Ok(val)) => { result.#field_ident = val; continue; }
Some(Err(err)) => return Err(err),
None => {},
}
});
},
None => {},
}
match &field.short_option {
Some(ref short_option) => {
let short_option = String::from("-") + short_option;
parser_components.extend(quote_spanned!{span=>
match <#field_type as jockey::Parsable>::parse_arg(&mut iter, &#short_option.to_string()) {
Some(Ok(val)) => { result.#field_ident = val; continue; }
Some(Err(err)) => return Err(err),
None => {},
}
});
}
None => {},
}
}
let unknown_args_component = match unknown_args_field {
Some(field) => {
let field_ident = &field.ident;
let field_type = &field.ty;
let span = field_ident.span();
quote_spanned!{span=>
match iter.next() {
Some(value) => <#field_type as std::iter::Extend<String>>::extend(&mut result.#field_ident, std::iter::once(value)),
None => {},
}
}
}
None => quote! {
return Err(jockey::Error::UnknownOption(iter.peek().unwrap().to_string()));
},
};
let struct_ident = &struct_def.ident;
let result = quote!{
fn parse_args<I> (args: I) -> jockey::Result<#struct_ident> where I : Iterator<Item = String> {
let mut result = <#struct_ident as Default>::default();
let mut iter = args.peekable();
iter.next();
loop {
if iter.peek().is_none() { break; }
#parser_components
#unknown_args_component
}
Ok(result)
}
};
result.into()
}