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 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
use proc_macro::TokenStream; use quote::quote; use syn::Ident; use syn::{parse_macro_input, DeriveInput}; fn _print_type_of<T>(_: &T) { println!("{}", std::any::type_name::<T>()) } #[proc_macro_derive(IntoDefault, attributes(IntoStruct, IntoType))] pub fn into_default(item: TokenStream) -> TokenStream { let ast = parse_macro_input!(item as DeriveInput); let attributes = &ast.attrs; let base_type = &ast.ident; let mut code: TokenStream = TokenStream::from(quote! {}); for attribute in attributes { if attribute.path.is_ident("IntoStruct") { let type_struct = attribute.parse_args::<Ident>().unwrap(); if let syn::Data::Struct(d) = &ast.data { if let syn::Fields::Named(f) = &d.fields { let fields = &f.named; let mut fields_name = Vec::new(); let mut fields_value = Vec::new(); for field in fields { let type_temp = &field.ident; let mut quote_temp = quote! {item.#type_temp.into()}; fields_name.push(&field.ident); if let syn::Type::Path(path) = &field.ty { for segment in &path.path.segments { if segment.ident == "Option" { quote_temp = quote! {match item.#type_temp { Some(value) => value.into(), None => Default::default() }}; } else if segment.ident == "Vec" { quote_temp = quote! {item.#type_temp.into_iter().map(|v| v.into()).collect::<Vec<_>>()}; } } } fields_value.push(quote_temp); } code = TokenStream::from(quote! { impl From<Option<#base_type>> for #type_struct { fn from(item: Option<#base_type>) -> Self { match item { Some(v) => v.into(), None => Default::default() } } } impl Into<Option<#type_struct>> for #base_type { fn into(self) -> Option<#type_struct> { Some(self.into()) } } impl Into<Vec<#type_struct>> for #base_type { fn into(self) -> Vec<#type_struct> { vec! {self.into()} } } impl From<#base_type> for #type_struct { fn from(item: #base_type) -> Self { #type_struct { #(#fields_name: #fields_value ,)* } } } }); } } } else { TokenStream::from(quote! {}); } } code }