clone-fields-derive 0.4.1

Derive macro for CloneFields trait
Documentation
use struct_data::StructData;
use syn::{
    self,
    parse::{Error, Parse, ParseStream, Result},
};

pub struct InputData {
    pub struct_data: StructData,
    pub destination_types: Vec<syn::Path>,
}

impl Parse for InputData {
    fn parse(input: ParseStream) -> Result<Self> {
        let input: syn::DeriveInput = Parse::parse(input)?;
        let destination_types = get_destinations(input.attrs)?;
        if destination_types.is_empty() {
            return Err(Error::new(
                input.ident.span(),
                "No destination types, specify at least one with `#[destinations(TypeName)]`",
            ));
        }
        let data = match input.data {
            syn::Data::Struct(data_struct) => data_struct,
            _ => {
                return Err(Error::new(
                    input.ident.span(),
                    "Only structs with name fields are supported",
                ))
            }
        };
        let struct_data = StructData::new(data, input.ident, input.generics);
        Ok(InputData {
            struct_data,
            destination_types,
        })
    }
}

fn get_destinations(attrs: Vec<syn::Attribute>) -> Result<Vec<syn::Path>> {
    attrs
        .into_iter()
        .filter(|attr| attr.path.is_ident("destinations"))
        .map(|attr| {
            let meta = attr
                .parse_meta()
                .expect("Destinations should be a list of quoted types");
            let meta_list = match meta {
                syn::Meta::List(list) => list,
                _ => panic!("Expected a list of type names"),
            };
            meta_list.nested.into_iter().map(|nested| match nested {
                syn::NestedMeta::Literal(syn::Lit::Str(lit_str)) => {
                    let path: syn::Path = lit_str.parse().unwrap();
                    Ok(path)
                }
                _ => panic!("Destinations should be a list of quoted types"),
            })
        })
        .flatten()
        .collect()
}