use ident_case::RenameRule;
use syn;
use ast::{Data, Fields, Style};
use codegen;
use options::{DefaultExpression, InputField, InputVariant, ParseAttribute, ParseData};
use {Error, FromMeta, Result};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Core {
pub ident: syn::Ident,
pub generics: syn::Generics,
pub default: Option<DefaultExpression>,
pub rename_rule: RenameRule,
pub map: Option<syn::Path>,
pub data: Data<InputVariant, InputField>,
pub bound: Option<Vec<syn::WherePredicate>>,
}
impl Core {
pub fn start(di: &syn::DeriveInput) -> Self {
Core {
ident: di.ident.clone(),
generics: di.generics.clone(),
data: Data::empty_from(&di.data),
default: Default::default(),
rename_rule: if let syn::Data::Enum(_) = di.data {
RenameRule::SnakeCase
} else {
Default::default()
},
map: Default::default(),
bound: Default::default(),
}
}
fn as_codegen_default<'a>(&'a self) -> Option<codegen::DefaultExpression<'a>> {
self.default.as_ref().map(|expr| match *expr {
DefaultExpression::Explicit(ref path) => codegen::DefaultExpression::Explicit(path),
DefaultExpression::Inherit | DefaultExpression::Trait => {
codegen::DefaultExpression::Trait
}
})
}
}
impl ParseAttribute for Core {
fn parse_nested(&mut self, mi: &syn::Meta) -> Result<()> {
match mi.name().to_string().as_str() {
"default" => {
if self.default.is_some() {
Err(Error::duplicate_field("default"))
} else {
self.default = FromMeta::from_meta(mi)?;
Ok(())
}
}
"rename_all" => {
self.rename_rule = FromMeta::from_meta(mi)?;
Ok(())
}
"map" => {
if self.map.is_some() {
Err(Error::duplicate_field("map"))
} else {
self.map = FromMeta::from_meta(mi)?;
Ok(())
}
}
"bound" => {
self.bound = FromMeta::from_meta(mi)?;
Ok(())
}
n => Err(Error::unknown_field(n.as_ref())),
}
}
}
impl ParseData for Core {
fn parse_variant(&mut self, variant: &syn::Variant) -> Result<()> {
let v = InputVariant::from_variant(variant, Some(&self))?;
match self.data {
Data::Enum(ref mut variants) => {
variants.push(v);
Ok(())
}
Data::Struct(_) => panic!("Core::parse_variant should never be called for a struct"),
}
}
fn parse_field(&mut self, field: &syn::Field) -> Result<()> {
let f = InputField::from_field(field, Some(&self))?;
match self.data {
Data::Struct(Fields {
style: Style::Unit, ..
}) => panic!("Core::parse_field should not be called on unit"),
Data::Struct(Fields { ref mut fields, .. }) => {
fields.push(f);
Ok(())
}
Data::Enum(_) => panic!("Core::parse_field should never be called for an enum"),
}
}
}
impl<'a> From<&'a Core> for codegen::TraitImpl<'a> {
fn from(v: &'a Core) -> Self {
codegen::TraitImpl {
ident: &v.ident,
generics: &v.generics,
data: v.data
.as_ref()
.map_struct_fields(InputField::as_codegen_field)
.map_enum_variants(|variant| variant.as_codegen_variant(&v.ident)),
default: v.as_codegen_default(),
map: v.map.as_ref(),
bound: v.bound.as_ref().map(|i| i.as_slice()),
}
}
}