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()
}