use proc_macro2::Span;
use syn::{parse_quote, spanned::Spanned};
use crate::ast::NestedMeta;
use crate::error::Accumulator;
use crate::{Error, FromMeta, Result};
mod core;
mod forward_attrs;
mod from_attributes;
mod from_derive;
mod from_field;
mod from_meta;
mod from_type_param;
mod from_variant;
mod input_field;
mod input_variant;
mod outer_from;
mod shape;
pub use self::core::Core;
pub use self::forward_attrs::{AttrsField, ForwardAttrsFilter};
pub use self::from_attributes::FromAttributesOptions;
pub use self::from_derive::FdiOptions;
pub use self::from_field::FromFieldOptions;
pub use self::from_meta::FromMetaOptions;
pub use self::from_type_param::FromTypeParamOptions;
pub use self::from_variant::FromVariantOptions;
pub use self::input_field::InputField;
pub use self::input_variant::InputVariant;
pub use self::outer_from::OuterFrom;
pub use self::shape::{DataShape, DeriveInputShapeSet};
#[derive(Debug, Clone)]
pub enum DefaultExpression {
Inherit,
Explicit(syn::Path),
Trait {
span: Span,
},
}
#[doc(hidden)]
impl FromMeta for DefaultExpression {
fn from_meta(item: &syn::Meta) -> Result<Self> {
match item {
syn::Meta::Path(_) => Ok(DefaultExpression::Trait { span: item.span() }),
syn::Meta::List(nm) => Err(Error::unsupported_format("list").with_span(nm)),
syn::Meta::NameValue(nv) => Self::from_expr(&nv.value),
}
}
fn from_expr(expr: &syn::Expr) -> Result<Self> {
syn::Path::from_expr(expr).map(DefaultExpression::Explicit)
}
fn from_value(value: &syn::Lit) -> Result<Self> {
syn::Path::from_value(value).map(DefaultExpression::Explicit)
}
}
pub trait ParseAttribute: Sized {
fn parse_attributes(mut self, attrs: &[syn::Attribute]) -> Result<Self> {
let mut errors = Error::accumulator();
for attr in attrs {
if attr.meta.path() == &parse_quote!(darling) {
errors.handle(parse_attr(attr, &mut self));
}
}
errors.finish_with(self)
}
fn parse_nested(&mut self, mi: &syn::Meta) -> Result<()>;
}
fn parse_attr<T: ParseAttribute>(attr: &syn::Attribute, target: &mut T) -> Result<()> {
let mut errors = Error::accumulator();
match &attr.meta {
syn::Meta::List(data) => {
for item in NestedMeta::parse_meta_list(data.tokens.clone())? {
if let NestedMeta::Meta(ref mi) = item {
errors.handle(target.parse_nested(mi));
} else {
panic!("Wasn't able to parse: `{:?}`", item);
}
}
errors.finish()
}
item => panic!("Wasn't able to parse: `{:?}`", item),
}
}
pub trait ParseData: Sized {
fn parse_body(mut self, body: &syn::Data) -> Result<Self> {
use syn::{Data, Fields};
let mut errors = Error::accumulator();
match *body {
Data::Struct(ref data) => match data.fields {
Fields::Unit => {}
Fields::Named(ref fields) => {
for field in &fields.named {
errors.handle(self.parse_field(field));
}
}
Fields::Unnamed(ref fields) => {
for field in &fields.unnamed {
errors.handle(self.parse_field(field));
}
}
},
Data::Enum(ref data) => {
for variant in &data.variants {
errors.handle(self.parse_variant(variant));
}
}
Data::Union(_) => unreachable!(),
};
self.validate_body(&mut errors);
errors.finish_with(self)
}
fn parse_variant(&mut self, variant: &syn::Variant) -> Result<()> {
Err(Error::unsupported_format("enum variant").with_span(variant))
}
fn parse_field(&mut self, field: &syn::Field) -> Result<()> {
Err(Error::unsupported_format("struct field").with_span(field))
}
#[allow(unused_variables)]
fn validate_body(&self, errors: &mut Accumulator) {}
}