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