use amplify_syn::{DeriveInner, Field, FieldKind, Items, NamedField, Variant};
use proc_macro2::{Span, TokenStream as TokenStream2};
use syn::{Error, Result};
use crate::params::{FieldAttr, StrictDerive, VariantAttr};
struct DeriveDumb<'a>(&'a StrictDerive);
impl StrictDerive {
pub fn derive_dumb(&self) -> Result<TokenStream2> {
self.data.derive(&self.conf.strict_crate, &ident!(StrictDumb), &DeriveDumb(self))
}
}
impl DeriveInner for DeriveDumb<'_> {
fn derive_unit_inner(&self) -> Result<TokenStream2> {
Ok(quote! {
fn strict_dumb() -> Self {
Self()
}
})
}
fn derive_struct_inner(&self, fields: &Items<NamedField>) -> Result<TokenStream2> {
if let Some(ref dumb_expr) = self.0.conf.dumb {
return Ok(quote! {
fn strict_dumb() -> Self {
#dumb_expr
}
});
}
let crate_name = &self.0.conf.strict_crate;
let trait_name = quote!(#crate_name::StrictDumb);
let mut items = Vec::with_capacity(fields.len());
for named in fields {
let attr = FieldAttr::with(named.field.attr.clone(), FieldKind::Named)?;
let name = &named.name;
items.push(match attr.dumb {
None => quote! { #name: StrictDumb::strict_dumb() },
Some(dumb_value) => quote! { #name: #dumb_value },
});
}
Ok(quote! {
fn strict_dumb() -> Self {
use #trait_name;
Self {
#( #items ),*
}
}
})
}
fn derive_tuple_inner(&self, fields: &Items<Field>) -> Result<TokenStream2> {
if let Some(ref dumb_expr) = self.0.conf.dumb {
return Ok(quote! {
fn strict_dumb() -> Self {
#dumb_expr
}
});
}
let crate_name = &self.0.conf.strict_crate;
let trait_name = quote!(#crate_name::StrictDumb);
let mut items = Vec::with_capacity(fields.len());
for field in fields {
let attr = FieldAttr::with(field.attr.clone(), FieldKind::Unnamed)?;
items.push(match attr.dumb {
None => quote! { StrictDumb::strict_dumb() },
Some(dumb_value) => quote! { #dumb_value },
});
}
Ok(quote! {
fn strict_dumb() -> Self {
use #trait_name;
Self(#( #items ),*)
}
})
}
fn derive_enum_inner(&self, variants: &Items<Variant>) -> Result<TokenStream2> {
if let Some(ref dumb_expr) = self.0.conf.dumb {
return Ok(quote! {
fn strict_dumb() -> Self {
#dumb_expr
}
});
}
let mut dumb_variant = None;
for variant in variants {
let attr = VariantAttr::try_from(variant.attr.clone())?;
let name = &variant.name;
if attr.dumb {
dumb_variant = Some(quote! { Self::#name });
}
}
let dumb_variant = dumb_variant.ok_or_else(|| {
Error::new(
Span::call_site(),
"enum must mark one of its variants with `#[strict_type(dumb)]` attribute, or \
provide a dumb value in eponym attribute at container level",
)
})?;
Ok(quote! {
fn strict_dumb() -> Self {
#dumb_variant
}
})
}
}