clone_fields_derive/
lib.rs1#[macro_use]
8extern crate quote;
9#[macro_use]
10extern crate syn;
11
12extern crate proc_macro;
13extern crate proc_macro2;
14
15mod input_data;
16mod struct_data;
17
18use self::{input_data::InputData, struct_data::StructData};
19use proc_macro::TokenStream;
20use quote::ToTokens;
21
22#[proc_macro_derive(CloneFields, attributes(destinations))]
40pub fn clone_fields_derive(input: TokenStream) -> TokenStream {
41 let InputData {
42 struct_data,
43 destination_types,
44 } = parse_macro_input!(input as InputData);
45 let impls = destination_types
46 .iter()
47 .map(|ty| clone_fields(&struct_data, ty));
48 quote!(
49 #(#impls)*
50 )
51 .into()
52}
53
54#[proc_macro_derive(MoveFields, attributes(destinations))]
69pub fn move_fields_derive(input: TokenStream) -> TokenStream {
70 let InputData {
71 struct_data,
72 destination_types,
73 } = parse_macro_input!(input as InputData);
74 let impls = destination_types
75 .iter()
76 .map(|ty| move_fields(&struct_data, ty));
77 quote!(
78 #(#impls)*
79 )
80 .into()
81}
82
83fn clone_fields(struct_data: &StructData, to_ty: &syn::Path) -> impl ToTokens {
84 let from_ty = &struct_data.name;
85 let fields = &struct_data.field_idents;
86 let (impl_generics, ty_generics, where_clause) = struct_data.generics.split_for_impl();
87 let direct_clones = fields
88 .iter()
89 .map(|field| quote!( #field: CloneInto::clone_into(&self.#field) ));
90 let reverse_clones = fields
91 .iter()
92 .map(|field| quote!( #field: CloneFrom::clone_from(&other.#field) ));
93 quote!(
94 impl #impl_generics CloneInto<#to_ty #ty_generics> for #from_ty #ty_generics #where_clause {
95 fn clone_into(&self) -> #to_ty #ty_generics {
96 #to_ty {
97 #( #direct_clones ),*
98 }
99 }
100 }
101
102 impl #impl_generics CloneFrom<#to_ty #ty_generics> for #from_ty #ty_generics #where_clause {
103 fn clone_from(other: &#to_ty #ty_generics) -> Self {
104 #from_ty {
105 #( #reverse_clones ),*
106 }
107 }
108 }
109 )
110}
111
112fn move_fields(struct_data: &StructData, to_ty: &syn::Path) -> impl ToTokens {
113 let (impl_generics, ty_generics, where_clause) = struct_data.generics.split_for_impl();
114 let into_fields = struct_data
115 .field_idents
116 .iter()
117 .map(|field| quote!( #field: Into::into(self.#field) ));
118 let from_fields = struct_data
119 .field_idents
120 .iter()
121 .map(|field| quote!( #field: From::from(other.#field) ));
122 let from_ty = &struct_data.name;
123 quote!(
124 impl #impl_generics Into<#to_ty #ty_generics> for #from_ty #ty_generics #where_clause {
125 fn into(self) -> #to_ty #ty_generics {
126 #to_ty {
127 #( #into_fields ),*
128 }
129 }
130 }
131
132 impl #impl_generics From<#to_ty #ty_generics> for #from_ty #ty_generics #where_clause {
133 fn from(other: #to_ty #ty_generics) -> Self {
134 #from_ty {
135 #( #from_fields ),*
136 }
137 }
138 }
139 )
140}