#![allow(clippy ::wildcard_imports)] #![allow(clippy ::unnecessary_wraps)] #![allow(clippy ::used_underscore_binding)] #![allow(clippy ::no_effect_underscore_binding)] #![allow(dead_code)] #![allow(unused_variables)]
use macro_tools :: { Result, generic_params ::GenericsRef, syn, proc_macro2 };
#[ cfg( feature = "former_diagnostics_print_generated" ) ]
use macro_tools ::diag;
use macro_tools ::quote :: { format_ident, quote };
use macro_tools ::proc_macro2 ::TokenStream;
use super ::struct_attrs ::ItemAttributes; use super ::field_attrs ::FieldAttributes;
mod common_emitters;
mod struct_multi_fields_scalar;
mod struct_multi_fields_subform;
mod struct_single_field_scalar;
mod struct_single_field_subform;
mod struct_zero_fields_handler;
mod tuple_multi_fields_scalar;
mod tuple_multi_fields_subform;
mod tuple_single_field_scalar;
mod tuple_single_field_subform;
mod tuple_zero_fields_handler;
mod unit_variant_handler;
#[ allow( dead_code ) ] pub(super) struct EnumVariantFieldInfo
{
pub ident: syn ::Ident,
pub ty: syn ::Type,
pub attrs: FieldAttributes,
pub is_constructor_arg: bool,
}
#[ allow( dead_code ) ] pub(super) struct EnumVariantHandlerContext< 'a >
{
pub ast: &'a syn ::DeriveInput,
pub variant: &'a syn ::Variant,
pub struct_attrs: &'a ItemAttributes,
pub enum_name: &'a syn ::Ident,
pub vis: &'a syn ::Visibility,
pub generics: &'a syn ::Generics,
pub original_input: &'a TokenStream,
pub variant_attrs: &'a FieldAttributes,
pub variant_field_info: &'a [EnumVariantFieldInfo],
pub merged_where_clause: Option< &'a syn ::WhereClause >,
pub methods: &'a mut Vec< TokenStream >,
pub end_impls: &'a mut Vec< TokenStream >,
pub standalone_constructors: &'a mut Vec< TokenStream >,
pub has_debug: bool,
}
#[ allow( clippy ::too_many_lines ) ]
pub(super) fn former_for_enum(
ast: &syn ::DeriveInput,
data_enum: &syn ::DataEnum,
original_input: &TokenStream,
item_attributes: &ItemAttributes, has_debug: bool,
) -> Result< TokenStream > {
let enum_name = &ast.ident;
let vis = &ast.vis;
let generics = &ast.generics;
let struct_attrs = item_attributes;
let mut methods = Vec ::new();
let mut end_impls = Vec ::new();
let generics_ref = GenericsRef ::new(generics);
let enum_type_path = generics_ref.type_path_tokens_if_any(enum_name);
let mut standalone_constructors = Vec ::new();
let merged_where_clause = generics.where_clause.as_ref();
for variant in &data_enum.variants
{
let variant_attrs = FieldAttributes ::from_attrs(variant.attrs.iter())?;
let variant_field_info: Vec< Result< EnumVariantFieldInfo >> = match &variant.fields
{
syn ::Fields ::Named(f) => f
.named
.iter()
.map(|field| {
let attrs = FieldAttributes ::from_attrs(field.attrs.iter())?;
let is_constructor_arg = if attrs.former_ignore.value(false)
{
false } else if attrs.arg_for_constructor.value(false)
{
true } else {
false };
Ok(EnumVariantFieldInfo {
ident: field
.ident
.clone()
.ok_or_else(|| syn ::Error ::new_spanned(field, "Named field requires an identifier"))?,
ty: field.ty.clone(),
attrs,
is_constructor_arg,
})
})
.collect(),
syn ::Fields ::Unnamed(f) => f
.unnamed
.iter()
.enumerate()
.map(|(index, field)| {
let attrs = FieldAttributes ::from_attrs(field.attrs.iter())?;
let is_constructor_arg = if attrs.former_ignore.value(false)
{
false } else if attrs.arg_for_constructor.value(false)
{
true } else {
false };
Ok(EnumVariantFieldInfo {
ident: format_ident!("_{}", index),
ty: field.ty.clone(),
attrs,
is_constructor_arg,
})
})
.collect(),
syn ::Fields ::Unit => vec![],
};
let variant_field_info: Vec< EnumVariantFieldInfo > = variant_field_info.into_iter().collect :: < Result< _ >>()?;
let mut ctx = EnumVariantHandlerContext {
ast,
variant,
struct_attrs,
enum_name,
vis,
generics,
original_input,
variant_attrs: &variant_attrs,
variant_field_info: &variant_field_info,
merged_where_clause,
methods: &mut methods,
end_impls: &mut end_impls,
standalone_constructors: &mut standalone_constructors,
has_debug,
};
match &ctx.variant.fields
{
syn ::Fields ::Unit =>
{
let generated = unit_variant_handler ::handle(&mut ctx)?;
ctx.methods.push(generated); }
syn ::Fields ::Unnamed(fields) => match fields.unnamed.len()
{
0 =>
{
let generated = tuple_zero_fields_handler ::handle(&mut ctx)?;
ctx.methods.push(generated); }
1 =>
{
if ctx.variant_attrs.scalar.is_some()
{
let generated = tuple_single_field_scalar ::handle(&mut ctx)?;
ctx.methods.push(generated); } else {
let generated = tuple_single_field_subform ::handle(&mut ctx)?;
ctx.methods.push(generated); }
}
_ =>
{
if ctx.variant_attrs.subform_scalar.is_some()
{
return Err(syn ::Error ::new_spanned(
ctx.variant,
"#[ subform_scalar ] cannot be used on tuple variants with multiple fields.",
));
}
if ctx.variant_attrs.scalar.is_some()
{
let generated = tuple_multi_fields_scalar ::handle(&mut ctx)?;
ctx.methods.push(generated); } else {
let generated = tuple_multi_fields_subform ::handle(&mut ctx)?;
ctx.methods.push(generated); }
}
},
syn ::Fields ::Named(fields) => match fields.named.len()
{
0 =>
{
if ctx.variant_attrs.subform_scalar.is_some()
{
return Err(syn ::Error ::new_spanned(
ctx.variant,
"#[ subform_scalar ] is not allowed on zero-field struct variants.",
));
}
if ctx.variant_attrs.scalar.is_none()
{
return Err(syn ::Error ::new_spanned(
ctx.variant,
"Zero-field struct variants require `#[ scalar ]` attribute for direct construction.",
));
}
let generated = struct_zero_fields_handler ::handle(&mut ctx)?;
ctx.methods.push(generated); }
_len =>
{
if ctx.variant_attrs.scalar.is_some()
{
if fields.named.len() == 1
{
let generated = struct_single_field_scalar ::handle(&mut ctx)?;
ctx.methods.push(generated); } else {
let generated = struct_multi_fields_scalar ::handle(&mut ctx)?;
ctx.methods.push(generated); }
} else if fields.named.len() == 1
{
let generated = struct_single_field_subform ::handle(&mut ctx)?;
ctx.methods.push(generated); } else {
let generated = struct_multi_fields_subform ::handle(&mut ctx)?;
ctx.methods.push(generated); }
}
},
}
}
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
#[ cfg( feature = "former_diagnostics_print_generated" ) ]
if has_debug
{
diag ::report_print(
format!("DEBUG: Raw generics for {enum_name}"),
original_input,
"e! { #generics },
);
diag ::report_print(
format!("DEBUG: impl_generics for {enum_name}"),
original_input,
"e! { #impl_generics },
);
diag ::report_print(
format!("DEBUG: ty_generics for {enum_name}"),
original_input,
"e! { #ty_generics },
);
diag ::report_print(
format!("DEBUG: where_clause for {enum_name}"),
original_input,
"e! { #where_clause },
);
}
let result = {
let impl_header = quote! { impl #impl_generics #enum_name #ty_generics };
#[ cfg( feature = "former_diagnostics_print_generated" ) ]
if has_debug
{
diag ::report_print(
format!("DEBUG: Methods collected before final quote for {enum_name}"),
original_input,
"e! { #( #methods )* },
);
diag ::report_print(
format!("DEBUG: Impl header for {enum_name}"),
original_input,
"e! { #impl_header },
);
}
quote! {
#( #end_impls )*
impl #impl_generics #enum_name #ty_generics
#where_clause
{
#( #methods )*
}
#( #standalone_constructors )*
}
};
#[ cfg( feature = "former_diagnostics_print_generated" ) ]
if has_debug
{
let about = format!("derive: Former\nenum: {enum_name}");
diag ::report_print(about, original_input, &result);
}
Ok(result)
}