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
60
61
62
extern crate proc_macro;

use proc_macro::TokenStream;
use quote::quote;
use syn;

#[proc_macro_derive(DynamoMapper)]
pub fn dynamo_mapper_macro_derive(input: TokenStream) -> TokenStream {
    let ast: syn::DeriveInput = syn::parse(input).unwrap();
    return implem_dynamo_mapper_macro(&ast);
}

fn implem_dynamo_mapper_macro(ast: &syn::DeriveInput) -> TokenStream {
    let name = &ast.ident;
    if let syn::Data::Struct(data) = &ast.data {
        let mut to_dynamo_lines = Vec::new();
        let mut from_dynamo_lines = Vec::new();

        for field in data.fields.iter() {
            if let Some(field_name) = &field.ident {
                let to_line = quote! {
                    if let Some(value) = self.#field_name.to_dynamo() {
                        item.insert(String::from(stringify!(#field_name)), value);
                    }
                };

                to_dynamo_lines.push(to_line);

                if let syn::Type::Path(type_path) = &field.ty {
                    from_dynamo_lines.push(quote! {
                        if let Some(field_value) = <#type_path>::from_dynamo(&item, String::from(stringify!(#field_name))) {
                            result.#field_name = field_value;
                        }
                    });
                }
                else {
                    panic!("Unknown type");
                };

            }
        }

        let gen = quote! {
            impl DynamoMapper for #name {
                fn to_dynamo(&self) -> DynamoItem {
                    let mut item = DynamoItem::new();
                    #(#to_dynamo_lines)*
                    return item;
                }

                fn from_dynamo(item: &DynamoItem) -> #name {
                    let mut result = #name {..Default::default()};
                    #(#from_dynamo_lines)*
                    return result;
                }
            }
        };
        gen.into()
    } else {
        panic!("Should only be used on struct");
    }
}