extendable_data_helpers/
lib.rs

1use proc_macro2::{Ident, Span};
2use proc_macro::TokenStream;
3use syn::{parse_macro_input, DeriveInput};
4use quote::quote;
5
6/// Procedural attribute macro that combines ("extends") data.
7///
8/// Generates a new procedural macro which allows you to extend some data structure A into data structure B. 
9///
10/// See extendable_data::combine_data for how the data is actually combined.
11#[proc_macro_attribute]
12pub fn extendable_data(args: TokenStream, source: TokenStream) -> TokenStream {
13    let mut name_string = args.to_string();
14    let mut source_ast = parse_macro_input!(source as DeriveInput);
15    if args.is_empty() {
16        name_string = format!("extend_from_{}", source_ast.ident);
17    }
18    let name = Ident::new(&name_string, Span::call_site());
19    let mut docs = Vec::new();
20    let mut attrs = Vec::new();
21    for attr in std::mem::take(&mut source_ast.attrs) {
22        let doc: bool = if let syn::Meta::NameValue(ref meta) = attr.meta {
23            if let Some(ident) = meta.path.get_ident() {
24                ident == "doc"
25            } else {
26                false
27            }
28        } else {
29            false
30        };
31        if doc {
32            docs.push(attr);
33        } else {
34            attrs.push(attr);
35        }
36    }
37    TokenStream::from(quote! {
38        #(#docs)*
39        #[proc_macro_attribute]
40        pub fn #name(args: proc_macro::TokenStream, dst: proc_macro::TokenStream) -> proc_macro::TokenStream {
41            let base = proc_macro2::TokenStream::from(quote::quote! {
42                #(#attrs)*
43                #source_ast
44            });
45            let dst_convert: proc_macro2::TokenStream = dst.into();
46            let args_convert: proc_macro2::TokenStream = args.into();
47            extendable_data::combine_data(base, dst_convert, Some(args_convert)).into()
48        }
49    })
50}