partial_derive 0.1.0

makes all the properties of a struct type an optional property
Documentation
use core::iter::FromIterator;
use proc_macro2::{Ident, Span};
use quote::{quote, ToTokens};
use syn::{DeriveInput, Fields, Type, Visibility};

#[proc_macro_derive(Partial)]
pub fn derive_partial(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let DeriveInput {
        attrs,
        vis,
        ident: ty,
        generics,
        data,
        ..
    } = syn::parse(input).unwrap();
    let mut derives = Vec::new();
    for attr in attrs.into_iter() {
        if attr.path.is_ident("derive") {
            derives.push(attr.into_token_stream());
        }
    }
    let derive = if derives.is_empty() {
        proc_macro2::TokenStream::new()
    } else {
        proc_macro2::TokenStream::from_iter(derives.into_iter())
    };
    let partial_ident = Ident::new(&format!("Partial{}", ty), Span::call_site());

    let fields = filter_fields(match data {
        syn::Data::Struct(ref s) => &s.fields,
        _ => panic!("Field can only be derived for structs"),
    });

    let _field_var = fields.iter().map(|(vis, ident, ty)| {
        quote! {
            #vis #ident: core::option::Option<#ty>
        }
    });
    let convert_branch = fields.iter().map(|(_vis, ident, _ty)| {
        quote! {
            #ident: Some(src.#ident)
        }
    });

    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

    let tokens = quote! {
        #derive
        #vis struct #partial_ident #ty_generics
            #where_clause
        {
            #(#_field_var),*
        }

        impl #impl_generics From<#ty #ty_generics> for #partial_ident #ty_generics
            #where_clause
        {
            fn from(src: #ty #ty_generics) -> #partial_ident #ty_generics {
                #partial_ident {
                    #(#convert_branch),*
                }
            }
        }
    };
    tokens.into()
}

fn filter_fields(fields: &Fields) -> Vec<(Visibility, Ident, Type)> {
    fields
        .iter()
        .filter_map(|field| {
            if field.ident.is_some() {
                let field_vis = field.vis.clone();
                let field_ident = field.ident.as_ref().unwrap().clone();
                let field_ty = field.ty.clone();
                Some((field_vis, field_ident, field_ty))
            } else {
                None
            }
        })
        .collect::<Vec<_>>()
}