use macro_tools :: { Result, diag, typ, syn, proc_macro2 };
use macro_tools ::proc_macro2 ::TokenStream;
use macro_tools ::quote :: { format_ident, quote, ToTokens };
use macro_tools ::syn ::spanned ::Spanned;
mod former_enum;
use former_enum ::former_for_enum;
mod former_struct;
use former_struct ::former_for_struct;
mod field_attrs;
use field_attrs :: *;
mod field;
use field :: *;
mod struct_attrs;
use struct_attrs :: *;
mod trait_detection;
mod raw_identifier_utils;
mod attribute_validation;
pub struct FormerDefinitionTypesGenerics< 'a >
{
pub impl_generics: &'a syn ::punctuated ::Punctuated< syn ::GenericParam, syn ::token ::Comma >,
pub ty_generics: &'a syn ::punctuated ::Punctuated< syn ::GenericParam, syn ::token ::Comma >,
pub where_clause: &'a syn ::punctuated ::Punctuated< syn ::WherePredicate, syn ::token ::Comma >,
}
impl ToTokens for FormerDefinitionTypesGenerics< '_ >
{
fn to_tokens(&self, tokens: &mut TokenStream)
{
self.impl_generics.to_tokens(tokens);
self.ty_generics.to_tokens(tokens);
self.where_clause.to_tokens(tokens);
}
}
#[ allow( clippy ::format_in_format_args, clippy ::unnecessary_wraps ) ]
pub fn mutator(
#[ allow( unused_variables ) ] item: &syn ::Ident,
#[ allow( unused_variables ) ] original_input: ¯o_tools ::proc_macro2 ::TokenStream,
mutator: &AttributeMutator,
#[ allow( unused_variables ) ] former_definition_types: &syn ::Ident,
generics: &FormerDefinitionTypesGenerics< '_ >,
former_definition_types_ref: &proc_macro2 ::TokenStream,
) -> Result< TokenStream > {
#[ allow( unused_variables ) ] let impl_generics = generics.impl_generics;
#[ allow( unused_variables ) ]
let ty_generics = generics.ty_generics;
let where_clause = generics.where_clause;
let former_mutator_code = if mutator.custom.value(false)
{
quote! {}
} else {
quote! {
impl< #impl_generics > former ::FormerMutator
for #former_definition_types_ref
where
#where_clause
{
}
}
};
if mutator.debug.value(false)
{
#[ cfg( feature = "former_diagnostics_print_generated" ) ]
{
let debug = format!(
r"
= Example of custom mutator
impl< {} > former ::FormerMutator
for
{former_definition_types} < {} >
where
{}
{{
/// Mutates the context and storage of the entity just before the formation process completes.
#[ inline ]
fn form_mutation
(
storage: &mut Self ::Storage,
context: &mut Option< Self ::Context >,
)
{{
// Example: Set a default value if field 'a' wasn't provided
// storage.a.get_or_insert_with( Default ::default );
}}
}}
",
format!("{}", quote! { #impl_generics }),
format!("{}", quote! { #ty_generics }),
format!("{}", quote! { #where_clause }),
);
let about = format!(
r"derive: Former
item: {item}",
);
diag ::report_print(about, original_input, debug);
}
}
Ok(former_mutator_code)
}
fn doc_generate(item: &syn ::Ident) -> (String, String)
{
let doc_former_mod = format!(
r" Implementation of former for [{item}].
"
);
let doc_former_struct = format!(
r"
Structure to form [{item}]. Represents a forming entity designed to construct objects through a builder pattern.
This structure holds temporary storage and context during the formation process and
utilizes a defined end strategy to finalize the object creation.
"
);
(doc_former_mod, doc_former_struct)
}
#[ allow( clippy ::too_many_lines ) ]
pub fn former(input: proc_macro ::TokenStream) -> Result< TokenStream >
{
let original_input: TokenStream = input.clone().into();
let ast = syn ::parse :: < syn ::DeriveInput >(input)?;
let item_attributes = struct_attrs ::ItemAttributes ::from_attrs(ast.attrs.iter())?;
let has_debug = item_attributes.debug.is_some();
let result = match ast.data
{
syn ::Data ::Struct(ref data_struct) =>
{
former_for_struct(&ast, data_struct, &original_input, &item_attributes, has_debug)
}
syn ::Data ::Enum(ref data_enum) =>
{
former_for_enum(&ast, data_enum, &original_input, &item_attributes, has_debug)
}
syn ::Data ::Union(_) =>
{
Err(syn ::Error ::new(ast.span(), "Former derive does not support unions"))
}
}?;
#[ cfg( debug_assertions ) ]
std ::fs ::write("/tmp/generated_former_code.rs", result.to_string()).ok();
if has_debug
{
#[ cfg( feature = "former_diagnostics_print_generated" ) ]
{
let about = format!("derive: Former\nstructure: {}", ast.ident);
diag ::report_print(about, &original_input, &result);
}
}
Ok(result)
}