default_conversion/
lib.rs

1use proc_macro::TokenStream;
2use quote::quote;
3use syn::Ident;
4use syn::{parse_macro_input, DeriveInput};
5
6fn _print_type_of<T>(_: &T) {
7    println!("{}", std::any::type_name::<T>())
8}
9
10#[proc_macro_derive(IntoDefault, attributes(IntoStruct, IntoType))]
11pub fn into_default(item: TokenStream) -> TokenStream {
12    let ast = parse_macro_input!(item as DeriveInput);
13    let attributes = &ast.attrs;
14    let base_type = &ast.ident;
15    let mut code: TokenStream = TokenStream::from(quote! {});
16    for attribute in attributes {
17        if attribute.path.is_ident("IntoStruct") {
18            let type_struct = attribute.parse_args::<Ident>().unwrap();
19            if let syn::Data::Struct(d) = &ast.data {
20                if let syn::Fields::Named(f) = &d.fields {
21                    let fields = &f.named;
22                    let mut fields_name = Vec::new();
23                    let mut fields_value = Vec::new();
24                    for field in fields {
25                        let type_temp = &field.ident;
26                        let mut quote_temp = quote! {item.#type_temp.into()};
27                        fields_name.push(&field.ident);
28                        if let syn::Type::Path(path) = &field.ty {
29                            for segment in &path.path.segments {
30                                if segment.ident == "Option" {
31                                    quote_temp = quote! {match item.#type_temp {
32                                        Some(value) => value.into(),
33                                        None => Default::default()
34                                    }};
35                                } else if segment.ident == "Vec" {
36                                    quote_temp = quote! {item.#type_temp.into_iter().map(|v| v.into()).collect::<Vec<_>>()};
37                                }
38                            }
39                        }
40                        fields_value.push(quote_temp);
41                    }
42                    code = TokenStream::from(quote! {
43                        impl From<Option<#base_type>> for #type_struct {
44                            fn from(item: Option<#base_type>) -> Self {
45                               match item {
46                                   Some(v) => v.into(),
47                                   None => Default::default()
48                               }
49                            }
50                        }
51
52                        impl Into<Option<#type_struct>> for #base_type {
53                            fn into(self) -> Option<#type_struct> {
54                                Some(self.into())
55                            }
56                        }
57
58                        impl Into<Vec<#type_struct>> for #base_type {
59                            fn into(self) -> Vec<#type_struct> {
60                                vec! {self.into()}
61                            }
62                        }
63
64                        impl From<#base_type> for #type_struct {
65                          fn from(item: #base_type) -> Self {
66                             #type_struct {
67                                #(#fields_name: #fields_value ,)*
68                             }
69                          }
70                        }
71
72                    });
73                }
74            }
75        } else {
76            TokenStream::from(quote! {});
77        }
78    }
79    code
80}