use darling::{
ast::{Data, Fields, Style},
util::Ignored,
FromDeriveInput, FromVariant,
};
use crate::from_impl::FromImpl;
#[derive(FromDeriveInput)]
#[darling(from_ident, attributes(from_variants), supports(enum_any))]
pub struct Container {
pub into: bool,
pub ident: syn::Ident,
generics: syn::Generics,
data: Data<Variant, Ignored>,
}
impl Container {
pub fn as_impls(&self) -> Vec<FromImpl<'_>> {
if let Some(variants) = self.data.as_ref().take_enum() {
variants
.into_iter()
.filter(|v| v.is_enabled())
.map(|item| FromImpl {
generics: &self.generics,
variant_ident: &item.ident,
variant_ty: item.ty().expect("Shape validation already took place"),
target_ident: &self.ident,
into: item.into.unwrap_or(self.into),
})
.collect()
} else {
panic!("FromVariants is not supported on structs");
}
}
}
impl From<syn::Ident> for Container {
fn from(ident: syn::Ident) -> Self {
Container {
ident,
into: false,
generics: Default::default(),
data: Data::Enum(vec![]),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, FromVariant)]
#[darling(from_ident, attributes(from_variants), and_then = "Self::validate")]
pub struct Variant {
ident: syn::Ident,
skip: Option<bool>,
into: Option<bool>,
fields: Fields<syn::Type>,
}
impl Variant {
fn validate(self) -> darling::Result<Self> {
if self.is_enabled() && !self.fields.is_newtype() {
let shape = if self.fields.is_tuple() {
"tuple"
} else if self.fields.is_struct() {
"struct"
} else if self.fields.is_unit() {
"unit"
} else {
"unknown"
};
Err(darling::Error::unsupported_shape(shape).with_span(&self.fields))
} else {
Ok(self)
}
}
pub fn is_enabled(&self) -> bool {
!(self.fields.is_unit() || self.skip.unwrap_or(false))
}
pub fn ty(&self) -> Option<&syn::Type> {
if let Fields {
style: Style::Tuple,
ref fields,
..
} = self.fields
{
fields.get(0)
} else {
None
}
}
}
impl From<syn::Ident> for Variant {
fn from(ident: syn::Ident) -> Self {
Variant {
ident,
skip: Default::default(),
into: Default::default(),
fields: Fields::new(Style::Unit, Vec::new()),
}
}
}