#[macro_use]
extern crate quote;
#[macro_use]
extern crate syn;
extern crate proc_macro;
extern crate proc_macro2;
mod input_data;
mod struct_data;
use self::{input_data::InputData, struct_data::StructData};
use proc_macro::TokenStream;
use quote::ToTokens;
#[proc_macro_derive(CloneFields, attributes(destinations))]
pub fn clone_fields_derive(input: TokenStream) -> TokenStream {
let InputData {
struct_data,
destination_types,
} = parse_macro_input!(input as InputData);
let impls = destination_types
.iter()
.map(|ty| clone_fields(&struct_data, ty));
quote!(
#(#impls)*
)
.into()
}
#[proc_macro_derive(MoveFields, attributes(destinations))]
pub fn move_fields_derive(input: TokenStream) -> TokenStream {
let InputData {
struct_data,
destination_types,
} = parse_macro_input!(input as InputData);
let impls = destination_types
.iter()
.map(|ty| move_fields(&struct_data, ty));
quote!(
#(#impls)*
)
.into()
}
fn clone_fields(struct_data: &StructData, to_ty: &syn::Path) -> impl ToTokens {
let from_ty = &struct_data.name;
let fields = &struct_data.field_idents;
let (impl_generics, ty_generics, where_clause) = struct_data.generics.split_for_impl();
let direct_clones = fields
.iter()
.map(|field| quote!( #field: CloneInto::clone_into(&self.#field) ));
let reverse_clones = fields
.iter()
.map(|field| quote!( #field: CloneFrom::clone_from(&other.#field) ));
quote!(
impl #impl_generics CloneInto<#to_ty #ty_generics> for #from_ty #ty_generics #where_clause {
fn clone_into(&self) -> #to_ty #ty_generics {
#to_ty {
#( #direct_clones ),*
}
}
}
impl #impl_generics CloneFrom<#to_ty #ty_generics> for #from_ty #ty_generics #where_clause {
fn clone_from(other: &#to_ty #ty_generics) -> Self {
#from_ty {
#( #reverse_clones ),*
}
}
}
)
}
fn move_fields(struct_data: &StructData, to_ty: &syn::Path) -> impl ToTokens {
let (impl_generics, ty_generics, where_clause) = struct_data.generics.split_for_impl();
let into_fields = struct_data
.field_idents
.iter()
.map(|field| quote!( #field: Into::into(self.#field) ));
let from_fields = struct_data
.field_idents
.iter()
.map(|field| quote!( #field: From::from(other.#field) ));
let from_ty = &struct_data.name;
quote!(
impl #impl_generics Into<#to_ty #ty_generics> for #from_ty #ty_generics #where_clause {
fn into(self) -> #to_ty #ty_generics {
#to_ty {
#( #into_fields ),*
}
}
}
impl #impl_generics From<#to_ty #ty_generics> for #from_ty #ty_generics #where_clause {
fn from(other: #to_ty #ty_generics) -> Self {
#from_ty {
#( #from_fields ),*
}
}
}
)
}