runix_derive/
lib.rs

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    // Parse the input tokens into a syntax tree.
8    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            // Tuple structs
33            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}