use quote::{Tokens, ToTokens};
use syn::Ident;
use ast::Fields;
use codegen::{Field, FieldsGen};
use codegen::error::{ErrorCheck, ErrorDeclaration};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Variant<'a> {
pub name_in_attr: &'a str,
pub variant_ident: &'a Ident,
pub ty_ident: &'a Ident,
pub data: Fields<Field<'a>>,
pub skip: bool,
}
impl<'a> Variant<'a> {
pub fn as_unit_match_arm(&'a self) -> UnitMatchArm<'a> {
UnitMatchArm(self)
}
pub fn as_data_match_arm(&'a self) -> DataMatchArm<'a> {
DataMatchArm(self)
}
}
pub struct UnitMatchArm<'a>(&'a Variant<'a>);
impl<'a> ToTokens for UnitMatchArm<'a> {
fn to_tokens(&self, tokens: &mut Tokens) {
let val: &Variant<'a> = self.0;
if val.skip {
return;
}
let name_in_attr = val.name_in_attr;
if val.data.is_unit() {
let variant_ident = val.variant_ident;
let ty_ident = val.ty_ident;
tokens.append_all(quote!(
#name_in_attr => ::darling::export::Ok(#ty_ident::#variant_ident),
));
} else {
tokens.append_all(quote!(
#name_in_attr => ::darling::export::Err(::darling::Error::unsupported_format("literal")),
));
}
}
}
pub struct DataMatchArm<'a>(&'a Variant<'a>);
impl<'a> ToTokens for DataMatchArm<'a> {
fn to_tokens(&self, tokens: &mut Tokens) {
let val: &Variant<'a> = self.0;
if val.skip {
return;
}
let name_in_attr = val.name_in_attr;
let variant_ident = val.variant_ident;
let ty_ident = val.ty_ident;
if val.data.is_unit() {
tokens.append_all(quote!(
#name_in_attr => ::darling::export::Err(::darling::Error::unsupported_format("list")),
));
return;
}
let vdg = FieldsGen(&val.data);
if val.data.is_struct() {
let declare_errors = ErrorDeclaration::new();
let check_errors = ErrorCheck::with_location(name_in_attr);
let require_fields = vdg.require_fields();
let decls = vdg.declarations();
let core_loop = vdg.core_loop();
let inits = vdg.initializers();
tokens.append_all(quote!(
#name_in_attr => {
if let ::syn::Meta::List(ref __data) = *__nested {
let __items = &__data.nested;
#declare_errors
#decls
#core_loop
#require_fields
#check_errors
::darling::export::Ok(#ty_ident::#variant_ident {
#inits
})
} else {
::darling::export::Err(::darling::Error::unsupported_format("non-list"))
}
}
));
} else if val.data.is_newtype() {
tokens.append_all(quote!(
#name_in_attr => {
::darling::export::Ok(
#ty_ident::#variant_ident(
::darling::FromMetaItem::from_meta_item(__nested)
.map_err(|e| e.at(#name_in_attr))?)
)
}
));
} else {
panic!("Match arms aren't supported for tuple variants yet");
}
}
}