use crate::variants_data_struct_field_attr_meta::VariantsDataStructFieldAttrMeta;
use crate::variants_data_struct_field_meta::VariantsDataStructFieldMeta;
pub(crate) struct VariantsDataStructDefs {
pub(crate) derived_struct: syn::ItemStruct,
pub(crate) variant_type_structs: Vec<syn::ItemStruct>,
}
struct VariantData {
field_attrs: Vec<syn::Attribute>,
field_vis: syn::Visibility,
field_name: syn::Ident,
field_ty: syn::Type,
variant_ty_def: Option<syn::ItemStruct>,
}
fn variants_data_struct_field(
attrs: Vec<syn::Attribute>,
vis: syn::Visibility,
ident: syn::Ident,
ty: syn::Type,
) -> syn::Field {
syn::Field {
attrs,
mutability: syn::FieldMutability::None,
vis,
ident: Some(ident),
colon_token: Some(syn::token::Colon {
spans: [proc_macro2::Span::call_site()],
}),
ty,
}
}
pub(crate) fn variants_data_struct_defs(
attrs: Vec<syn::Attribute>,
variants_tys_attrs: Vec<syn::Attribute>,
variants_data_struct_vis: syn::Visibility,
struct_name: syn::Ident,
enum_generics: syn::Generics,
variants: syn::punctuated::Punctuated<syn::Variant, syn::Token![,]>,
) -> syn::Result<VariantsDataStructDefs> {
let variant_data_iter = variants.into_iter().map(|variant| {
let variants_data_struct_field_attr_meta: VariantsDataStructFieldAttrMeta =
VariantsDataStructFieldAttrMeta::from_attrs(&variant.attrs)?.unwrap_or_default();
let VariantsDataStructFieldMeta {
field_attrs,
field_vis,
field_name,
field_ty,
variant_ty,
} = VariantsDataStructFieldMeta::resolve(
variants_data_struct_field_attr_meta,
&variants_tys_attrs,
variants_data_struct_vis.clone(),
&variant,
);
let variant_ty_def = variant_ty.map(|variant_ty| variant_ty.to_struct_def(variant.fields));
let variant_data = VariantData {
field_attrs,
field_vis,
field_name,
field_ty,
variant_ty_def,
};
syn::Result::Ok(variant_data)
});
let mut variant_ty_defs: Vec<syn::ItemStruct> = vec![];
let mut struct_fields: Vec<syn::Field> = vec![];
for variant_data in variant_data_iter {
let VariantData {
field_attrs,
field_name,
field_vis,
field_ty,
variant_ty_def,
} = variant_data?;
if let Some(def) = variant_ty_def {
variant_ty_defs.push(def);
}
let field =
variants_data_struct_field(field_attrs, field_vis, field_name.clone(), field_ty);
struct_fields.push(field);
}
let delim_span: proc_macro2::extra::DelimSpan = {
let group = proc_macro2::Group::new(
proc_macro2::Delimiter::Brace,
proc_macro2::TokenStream::new(),
);
group.delim_span()
};
let derived_struct = syn::ItemStruct {
attrs,
vis: variants_data_struct_vis,
struct_token: syn::token::Struct {
span: struct_name.span(),
},
ident: struct_name,
generics: enum_generics,
fields: syn::Fields::Named(syn::FieldsNamed {
brace_token: syn::token::Brace { span: delim_span },
named: syn::punctuated::Punctuated::from_iter(struct_fields),
}),
semi_token: None,
};
Ok(VariantsDataStructDefs {
derived_struct,
variant_type_structs: variant_ty_defs,
})
}