1use proc_macro2::TokenStream;
2use quote::quote;
3use syn::{parse_macro_input, DeriveInput};
4
5#[proc_macro_derive(ToArgs)]
6pub fn to_args_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
7 let ast = parse_macro_input!(input as DeriveInput);
9
10 impl_to_args(&ast)
11 .unwrap_or_else(|err| err.to_compile_error())
12 .into()
13}
14
15fn impl_to_args(ast: &syn::DeriveInput) -> Result<TokenStream, syn::Error> {
16 let name = &ast.ident;
17 let fields = match ast.data {
18 syn::Data::Struct(ref s) => &s.fields,
19 _ => Err(syn::Error::new(
20 ast.ident.span(),
21 "`ToArgs` can only be derived from structs",
22 ))?,
23 };
24
25 let generics = &ast.generics;
26
27 let conversions = fields
28 .iter()
29 .enumerate()
30 .map(|(n, field)| match field.ident {
31 Some(ref i) => quote! { self.#i.to_args() },
32 None => quote! { self.#n.to_args() },
34 })
35 .collect::<Vec<_>>();
36
37 let len = conversions.len();
38
39 let gen = quote! {
40 impl #generics ToArgs for #name #generics {
41 fn to_args(&self) -> ::std::vec::Vec<::std::string::String> {
42 let args: [::std::vec::Vec<::std::string::String>; #len] = [
43 #(#conversions),*
44 ];
45
46 args
47 .into_iter()
48 .flatten()
49 .collect()
50 }
51 }
52 };
53 Ok(gen)
54}