fields-converter-derive 0.1.4

Fields-wise type conversions derive macros
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>,
    pub derives: Vec<syn::Ident>,
}

impl Parse for InputData {
    fn parse(input: ParseStream) -> Result<Self> {
        let input: syn::DeriveInput = Parse::parse(input)?;
        let destination_types = get_destinations(&input.attrs)?;
        let derives = get_add_derives(&input.attrs);
        if destination_types.is_empty() {
            return Err(Error::new(
                input.ident.span(),
                r#"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 are supported")),
        };
        let struct_data = StructData::new(&data, input.ident, input.generics);
        Ok(InputData {
            struct_data,
            destination_types,
            derives,
        })
    }
}

fn get_destinations(attrs: &[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)) => lit_str.parse::<syn::Path>(),
                _ => panic!("Destinations should be a list of quoted types"),
            })
        })
        .flatten()
        .collect()
}

fn get_add_derives(attrs: &[syn::Attribute]) -> Vec<syn::Ident> {
    attrs
        .into_iter()
        .filter(|attr| attr.path.is_ident("add_derives"))
        .map(|attr| {
            let meta = attr
                .parse_meta()
                .expect("Destinations should be a list of autoderive macros");
            let meta_list = match meta {
                syn::Meta::List(list) => list,
                _ => panic!("Expected a list of names"),
            };
            meta_list.nested.into_iter().map(|nested| match nested {
                syn::NestedMeta::Meta(syn::Meta::Word(id)) => id,
                _ => panic!("Destinations should be a list of quoted types"),
            })
        })
        .flatten()
        .collect()
}