diff --git a/module/core/component_model/Readme.md b/module/core/component_model/Readme.md index d3c6e9109c..da35c2daa9 100644 --- a/module/core/component_model/Readme.md +++ b/module/core/component_model/Readme.md @@ -1,6 +1,6 @@ -# Module :: component_model +# Module :: `component_model` [![experimental](https://raster.shields.io/static/v1?label=&message=experimental&color=orange)](https://github.com/emersion/stability-badges#experimental) [![rust-status](https://github.com/Wandalen/wTools/actions/workflows/module_component_model_push.yml/badge.svg)](https://github.com/Wandalen/wTools/actions/workflows/module_component_model_push.yml) @@ -47,19 +47,19 @@ where } } -fn main() { +//fn main() { let mut person = Person::default(); person.assign(42); person.assign("Alice"); assert_eq!(person, Person { age: 42, name: "Alice".to_string() }); -} +//} ``` ## API Overview -- **Assign**: Generic trait for assigning values to struct fields by type. -- **AssignWithType**: Trait for assigning values with explicit type annotation. -- **ComponentsAssign**: Trait for assigning multiple components at once. +- **`Assign`**: Generic trait for assigning values to struct fields by type. +- **`AssignWithType`**: Trait for assigning values with explicit type annotation. +- **`ComponentsAssign`**: Trait for assigning multiple components at once. See [component_model_types documentation](https://docs.rs/component_model_types) for details. diff --git a/module/core/component_model/src/lib.rs b/module/core/component_model/src/lib.rs index 3936f30cfb..6b567e81a2 100644 --- a/module/core/component_model/src/lib.rs +++ b/module/core/component_model/src/lib.rs @@ -26,10 +26,7 @@ pub mod dependency #[ cfg( feature = "enabled" ) ] pub use own::*; -#[ allow( unused_imports ) ] -#[ cfg( feature = "enabled" ) ] // Former macro is intentionally not re-exported; all coupling with "former" is removed. - /// Own namespace of the module. #[ cfg( feature = "enabled" ) ] #[ allow( unused_imports ) ] diff --git a/module/core/component_model_meta/Readme.md b/module/core/component_model_meta/Readme.md index 19689cde07..4945def390 100644 --- a/module/core/component_model_meta/Readme.md +++ b/module/core/component_model_meta/Readme.md @@ -5,7 +5,7 @@ [![experimental](https://raster.shields.io/static/v1?label=&message=experimental&color=orange)](https://github.com/emersion/stability-badges#experimental) [![rust-status](https://github.com/Wandalen/wTools/actions/workflows/module_component_model_meta_push.yml/badge.svg)](https://github.com/Wandalen/wTools/actions/workflows/module_component_model_meta_push.yml) [![docs.rs](https://img.shields.io/docsrs/component_model_meta?color=e3e8f0&logo=docs.rs)](https://docs.rs/component_model_meta) [![discord](https://img.shields.io/discord/872391416519737405?color=eee&logo=discord&logoColor=eee&label=ask)](https://discord.gg/m3YfbXpUUY) -A flexible implementation of the Builder pattern supporting nested builders and collection-specific subcomponent_models. Implementation of its derive macro. Should not be used independently, instead use `module::component_model` which relies on the module. +A flexible implementation of the Builder pattern supporting nested builders and collection-specific `subcomponent_models`. Implementation of its derive macro. Should not be used independently, instead use `module::component_model` which relies on the module. Not intended to be used without runtime. This module and runtime is aggregate in `module::component_model` is [here](https://github.com/Wandalen/wTools/tree/master/module/core/component_model). diff --git a/module/core/former_meta/src/derive_former/former_enum.rs b/module/core/former_meta/src/derive_former/former_enum.rs index c9ef2bcd9c..8f0ef4c397 100644 --- a/module/core/former_meta/src/derive_former/former_enum.rs +++ b/module/core/former_meta/src/derive_former/former_enum.rs @@ -148,7 +148,7 @@ pub(super) struct EnumVariantHandlerContext< 'a > pub has_debug : bool, } - +#[allow(clippy::too_many_lines)] pub(super) fn former_for_enum ( ast : &syn::DeriveInput, @@ -211,7 +211,7 @@ pub(super) fn former_for_enum { ast, variant, - struct_attrs : &struct_attrs, + struct_attrs, enum_name, vis, generics, @@ -266,11 +266,11 @@ pub(super) fn former_for_enum { return Err( syn::Error::new_spanned( ctx.variant, "#[subform_scalar] is not allowed on zero-field struct variants." ) ); } - if !ctx.variant_attrs.scalar.is_some() + 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)?; + let generated = struct_zero_fields_handler::handle(&mut ctx); ctx.methods.push(generated); // Collect generated tokens } _len => @@ -284,23 +284,21 @@ pub(super) fn former_for_enum } else { - let generated = struct_multi_fields_scalar::handle(&mut ctx)?; + let generated = struct_multi_fields_scalar::handle(&mut ctx); ctx.methods.push(generated); // Collect generated tokens } } + else if fields.named.len() == 1 + { + let generated = struct_single_field_subform::handle(&mut ctx)?; + ctx.methods.push(generated); // Collect generated tokens + } else { - if fields.named.len() == 1 - { - let generated = struct_single_field_subform::handle(&mut ctx)?; - ctx.methods.push(generated); // Collect generated tokens - } - else - { - let generated = struct_multi_fields_subform::handle(&mut ctx)?; - ctx.methods.push(generated); // Collect generated tokens - } + let generated = struct_multi_fields_subform::handle(&mut ctx); + ctx.methods.push(generated); // Collect generated tokens } + } } } // End of match @@ -329,7 +327,7 @@ pub(super) fn former_for_enum if has_debug { - let about = format!( "derive : Former\nenum : {}", enum_name ); + let about = format!( "derive : Former\nenum : {enum_name}" ); diag::report_print( about, original_input, &result ); } diff --git a/module/core/former_meta/src/derive_former/former_enum/common_emitters.rs b/module/core/former_meta/src/derive_former/former_enum/common_emitters.rs index 8343c31e5e..d43427061c 100644 --- a/module/core/former_meta/src/derive_former/former_enum/common_emitters.rs +++ b/module/core/former_meta/src/derive_former/former_enum/common_emitters.rs @@ -1,14 +1,14 @@ // qqq : Implement shared emitter functions use super::*; -use macro_tools::{ Result, quote::{ quote } }; +use macro_tools::{ quote::{ quote } }; use proc_macro2::TokenStream; // Corrected import for TokenStream // use super::EnumVariantHandlerContext; #[allow(dead_code)] // Suppress warning about unused function -pub( crate ) fn generate_direct_constructor_for_variant( _ctx : &EnumVariantHandlerContext< '_ > ) -> Result< TokenStream > +pub( crate ) fn generate_direct_constructor_for_variant( _ctx : &EnumVariantHandlerContext< '_ > ) -> TokenStream { // qqq : Implement - Ok( quote!{} ) + quote!{} } // qqq : Add other placeholder functions as needed \ No newline at end of file diff --git a/module/core/former_meta/src/derive_former/former_enum/struct_multi_fields_scalar.rs b/module/core/former_meta/src/derive_former/former_enum/struct_multi_fields_scalar.rs index 048c21f79c..0ca5b8d1fe 100644 --- a/module/core/former_meta/src/derive_former/former_enum/struct_multi_fields_scalar.rs +++ b/module/core/former_meta/src/derive_former/former_enum/struct_multi_fields_scalar.rs @@ -1,13 +1,13 @@ // qqq : Implement logic for Struct { f1:T1, ... } with #[scalar] use super::*; -use macro_tools::{ Result, quote, syn }; +use macro_tools::{ quote, syn }; use super::EnumVariantHandlerContext; use proc_macro2::TokenStream; // Import TokenStream use convert_case::{ Case, Casing }; // Import Case and Casing from convert_case #[allow(dead_code)] // Suppress warning about unused function -pub( crate ) fn handle( ctx : &mut EnumVariantHandlerContext< '_ > ) -> Result< TokenStream > +pub( crate ) fn handle( ctx : &mut EnumVariantHandlerContext< '_ > ) -> TokenStream { // This handler is specifically for Struct { f1: T1, ... } variants with #[scalar]. // The main dispatch should ensure this is only called for such variants. @@ -73,5 +73,5 @@ pub( crate ) fn handle( ctx : &mut EnumVariantHandlerContext< '_ > ) -> Result< generated_tokens.extend(generated_standalone); } - Ok( generated_tokens ) + generated_tokens } \ No newline at end of file diff --git a/module/core/former_meta/src/derive_former/former_enum/struct_multi_fields_subform.rs b/module/core/former_meta/src/derive_former/former_enum/struct_multi_fields_subform.rs index b6201a4f8e..5dc29af6c9 100644 --- a/module/core/former_meta/src/derive_former/former_enum/struct_multi_fields_subform.rs +++ b/module/core/former_meta/src/derive_former/former_enum/struct_multi_fields_subform.rs @@ -1,13 +1,13 @@ // qqq : Implement logic for Struct { f1:T1, ... } with #[subform_scalar] or default use super::*; -use macro_tools::{ Result, quote, syn }; +use macro_tools::{ quote, syn }; use super::EnumVariantHandlerContext; use proc_macro2::TokenStream; // Import TokenStream use convert_case::{ Case, Casing }; // Import Case and Casing from convert_case #[allow(dead_code)] // Suppress warning about unused function -pub( crate ) fn handle( ctx : &mut EnumVariantHandlerContext< '_ > ) -> Result< TokenStream > +pub( crate ) fn handle( ctx : &mut EnumVariantHandlerContext< '_ > ) -> TokenStream { // This handler is specifically for Struct { f1: T1, ... } variants with #[subform_scalar] or default behavior. // The main dispatch should ensure this is only called for such variants. @@ -55,5 +55,5 @@ pub( crate ) fn handle( ctx : &mut EnumVariantHandlerContext< '_ > ) -> Result< // This will likely involve using common_emitters or dedicated logic here. // For now, just returning the method/constructor tokens. - Ok( generated_tokens ) + generated_tokens } \ No newline at end of file diff --git a/module/core/former_meta/src/derive_former/former_enum/struct_single_field_scalar.rs b/module/core/former_meta/src/derive_former/former_enum/struct_single_field_scalar.rs index d958325824..a30ccd2573 100644 --- a/module/core/former_meta/src/derive_former/former_enum/struct_single_field_scalar.rs +++ b/module/core/former_meta/src/derive_former/former_enum/struct_single_field_scalar.rs @@ -17,7 +17,7 @@ pub( crate ) fn handle( ctx : &mut EnumVariantHandlerContext< '_ > ) -> Result< let vis = &ctx.vis; // Get visibility // Get the single field's type and identifier - let field = ctx.variant_field_info.get(0).ok_or_else(|| { + let field = ctx.variant_field_info.first().ok_or_else(|| { syn::Error::new_spanned(ctx.variant, "Struct variant with #[scalar] must have exactly one field.") })?; let field_ident = &field.ident; diff --git a/module/core/former_meta/src/derive_former/former_enum/struct_single_field_subform.rs b/module/core/former_meta/src/derive_former/former_enum/struct_single_field_subform.rs index 397b34d2d9..49b650a7d0 100644 --- a/module/core/former_meta/src/derive_former/former_enum/struct_single_field_subform.rs +++ b/module/core/former_meta/src/derive_former/former_enum/struct_single_field_subform.rs @@ -18,46 +18,59 @@ pub( crate ) fn handle( ctx : &mut EnumVariantHandlerContext< '_ > ) -> Result< // Decompose generics for use in signatures (impl_generics and ty_generics are needed from local decomposition) let ( _def_generics, impl_generics, ty_generics, _local_where_clause_option_unused ) = // Renamed to avoid confusion - macro_tools::generic_params::decompose(&ctx.generics); + macro_tools::generic_params::decompose( ctx.generics ); // Use merged_where_clause from the context for any top-level item's where clause (like standalone fns or VariantFormer struct) - let top_level_where_clause = match ctx.merged_where_clause { // Use ctx.merged_where_clause - Some(clause) => quote! { where #clause }, // Add `where` keyword if clause exists - None => quote! {}, + let top_level_where_clause = match ctx.merged_where_clause + { // Use ctx.merged_where_clause + Some( clause ) => quote! { where #clause }, // Add `where` keyword if clause exists + None => quote! {}, }; // Get the single field's info - let field_info = ctx.variant_field_info.get(0).ok_or_else(|| { - syn::Error::new_spanned(ctx.variant, "Struct variant with subform behavior must have exactly one field for this handler.") + let field_info = ctx.variant_field_info.first().ok_or_else( + || + { + syn::Error::new_spanned( ctx.variant, "Struct variant with subform behavior must have exactly one field for this handler." ) })?; let field_name_original = &field_info.ident; // This is the original field name from the enum variant let field_ty = &field_info.ty; // Generate the name for the implicit variant former, make it generic if enum is generic - let variant_former_name_str = format!("{}{}Former", enum_ident, variant_ident); - let variant_former_ident = format_ident!("{}", variant_former_name_str); - let variant_former_name_generic = if ctx.generics.params.is_empty() { - quote! { #variant_former_ident } - } else { - quote! { #variant_former_ident< #ty_generics > } + let variant_former_name_str = format!( "{enum_ident}{variant_ident}Former" ); + let variant_former_ident = format_ident!( "{}", variant_former_name_str ); + let variant_former_name_generic = if ctx.generics.params.is_empty() + { + quote! { #variant_former_ident } + } + else + { + quote! { #variant_former_ident< #ty_generics > } }; // Correctly create method_ident for the accessor method, handling raw identifiers - let method_ident = { - let name_str = variant_ident.to_string(); - // Raw identifier check (consistent with other handlers) - if let Some(core_name) = name_str.strip_prefix("r#") { - let snake_core_name = core_name.to_case(Case::Snake); - syn::Ident::new_raw(&snake_core_name, variant_ident.span()) - } else { - let snake_name = name_str.to_case(Case::Snake); - let is_keyword = matches!(snake_name.as_str(), "as" | "async" | "await" | "break" | "const" | "continue" | "crate" | "dyn" | "else" | "enum" | "extern" | "false" | "fn" | "for" | "if" | "impl" | "in" | "let" | "loop" | "match" | "mod" | "move" | "mut" | "pub" | "ref" | "return" | "Self" | "self" | "static" | "struct" | "super" | "trait" | "true" | "type" | "unsafe" | "use" | "where" | "while" | "union" ); - if is_keyword { - syn::Ident::new_raw(&snake_name, variant_ident.span()) - } else { - syn::Ident::new(&snake_name, variant_ident.span()) - } + let method_ident = + { + let name_str = variant_ident.to_string(); + // Raw identifier check (consistent with other handlers) + if let Some( core_name ) = name_str.strip_prefix( "r#" ) + { + let snake_core_name = core_name.to_case( Case::Snake ); + syn::Ident::new_raw( &snake_core_name, variant_ident.span() ) + } + else + { + let snake_name = name_str.to_case( Case::Snake ); + let is_keyword = matches!( snake_name.as_str(), "as" | "async" | "await" | "break" | "const" | "continue" | "crate" | "dyn" | "else" | "enum" | "extern" | "false" | "fn" | "for" | "if" | "impl" | "in" | "let" | "loop" | "match" | "mod" | "move" | "mut" | "pub" | "ref" | "return" | "Self" | "self" | "static" | "struct" | "super" | "trait" | "true" | "type" | "unsafe" | "use" | "where" | "while" | "union" ); + if is_keyword + { + syn::Ident::new_raw( &snake_name, variant_ident.span() ) + } + else + { + syn::Ident::new( &snake_name, variant_ident.span() ) } + } }; // Generate the static method: Enum::variant_name() -> VariantFormer<...> diff --git a/module/core/former_meta/src/derive_former/former_enum/struct_zero_fields_handler.rs b/module/core/former_meta/src/derive_former/former_enum/struct_zero_fields_handler.rs index ed62022706..c25037687e 100644 --- a/module/core/former_meta/src/derive_former/former_enum/struct_zero_fields_handler.rs +++ b/module/core/former_meta/src/derive_former/former_enum/struct_zero_fields_handler.rs @@ -1,11 +1,11 @@ use super::*; -use macro_tools::{ Result, quote }; +use macro_tools::quote; use proc_macro2::TokenStream; // Corrected import for TokenStream // use former_types::FormerDefinition; // Not needed here /// Handles zero-field struct variants with the `#[scalar]` attribute. /// Returns generated tokens for the static method and optionally the standalone constructor. -pub( crate ) fn handle( ctx : &mut EnumVariantHandlerContext< '_ > ) -> Result< TokenStream > +pub( crate ) fn handle( ctx : &mut EnumVariantHandlerContext< '_ > ) -> TokenStream { // This handler is specifically for variants with #[scalar] // The main dispatch should ensure this is only called for scalar zero-field struct variants. @@ -52,5 +52,5 @@ pub( crate ) fn handle( ctx : &mut EnumVariantHandlerContext< '_ > ) -> Result< // and place them in the correct scope (outside the enum impl block). } - Ok( generated_tokens ) + generated_tokens } \ No newline at end of file diff --git a/module/core/former_meta/src/derive_former/former_enum/tuple_single_field_scalar.rs b/module/core/former_meta/src/derive_former/former_enum/tuple_single_field_scalar.rs index 42c06c1dcc..98eef680c0 100644 --- a/module/core/former_meta/src/derive_former/former_enum/tuple_single_field_scalar.rs +++ b/module/core/former_meta/src/derive_former/former_enum/tuple_single_field_scalar.rs @@ -19,7 +19,7 @@ pub( crate ) fn handle( ctx : &mut EnumVariantHandlerContext< '_ > ) -> Result< // Decompose generics for use in signatures (impl_generics and ty_generics are needed) let ( _def_generics, impl_generics, ty_generics, _local_where_clause_option ) = - macro_tools::generic_params::decompose(&ctx.generics); + macro_tools::generic_params::decompose(ctx.generics); // Use merged_where_clause from the context for the standalone constructor's where clause let where_clause = match ctx.merged_where_clause { @@ -28,7 +28,7 @@ pub( crate ) fn handle( ctx : &mut EnumVariantHandlerContext< '_ > ) -> Result< }; // Get the single field's type and identifier - let field = ctx.variant_field_info.get(0).ok_or_else(|| { + let field = ctx.variant_field_info.first().ok_or_else(|| { syn::Error::new_spanned(ctx.variant, "Tuple variant with #[scalar] must have exactly one field.") })?; let field_ty = &field.ty; diff --git a/module/core/former_meta/src/derive_former/former_enum/tuple_single_field_subform.rs b/module/core/former_meta/src/derive_former/former_enum/tuple_single_field_subform.rs index b17fb0773f..defaae9443 100644 --- a/module/core/former_meta/src/derive_former/former_enum/tuple_single_field_subform.rs +++ b/module/core/former_meta/src/derive_former/former_enum/tuple_single_field_subform.rs @@ -13,16 +13,15 @@ pub( crate ) fn handle( ctx : &mut EnumVariantHandlerContext< '_ > ) -> Result< // The main dispatch should ensure this is only called for such variants. let variant_ident = &ctx.variant.ident; - let _enum_ident = &ctx.enum_name; let vis = &ctx.vis; // Get visibility // Get the single field's type - let field = ctx.variant_field_info.get(0).ok_or_else(|| { + let field = ctx.variant_field_info.first().ok_or_else(|| { syn::Error::new_spanned(ctx.variant, "Tuple variant with subform behavior must have exactly one field.") })?; let field_ty = &field.ty; - let type_path_str = quote!{ #field_ty }.to_string().replace(" ", ""); + let type_path_str = quote!{ #field_ty }.to_string().replace(' ', ""); let is_phantom_data_field = type_path_str.starts_with("core::marker::PhantomData") || type_path_str.starts_with("std::marker::PhantomData"); let method_ident_string = variant_ident.to_string().to_case( Case::Snake ); diff --git a/module/core/former_meta/src/derive_former/former_enum/tuple_zero_fields_handler.rs b/module/core/former_meta/src/derive_former/former_enum/tuple_zero_fields_handler.rs index 927b6df7d0..2a6f192f52 100644 --- a/module/core/former_meta/src/derive_former/former_enum/tuple_zero_fields_handler.rs +++ b/module/core/former_meta/src/derive_former/former_enum/tuple_zero_fields_handler.rs @@ -24,7 +24,7 @@ pub( crate ) fn handle( ctx : &mut EnumVariantHandlerContext< '_ > ) -> Result< // Decompose generics (we need impl_generics and ty_generics from this) let ( _def_generics, impl_generics, ty_generics, _local_where_clause_option_unused ) = // Renamed to avoid confusion - macro_tools::generic_params::decompose(&ctx.generics); + macro_tools::generic_params::decompose(ctx.generics); // Use merged_where_clause from the context for the standalone constructor's where clause let top_level_where_clause = match ctx.merged_where_clause { // Use ctx.merged_where_clause @@ -65,15 +65,19 @@ pub( crate ) fn handle( ctx : &mut EnumVariantHandlerContext< '_ > ) -> Result< let fn_signature_generics = if ctx.generics.params.is_empty() { quote!{} } else { quote!{ < #impl_generics > } }; let return_type_generics = if ctx.generics.params.is_empty() { quote!{} } else { quote!{ < #ty_generics > } }; - let enum_path_for_construction = if ctx.generics.params.is_empty() { - quote!{ #enum_ident } - } else { - if ty_generics.is_empty() { quote!{ #enum_ident } } else { quote!{ #enum_ident::< #ty_generics > } } + // FIX: Combine the two conditions with identical blocks using || + let enum_path_for_construction = if ctx.generics.params.is_empty() || ty_generics.is_empty() + { + quote!{ #enum_ident } + } + else + { + quote!{ #enum_ident::< #ty_generics > } }; // Create unique name for standalone constructor: [enum_name]_[variant_snake_case] - let standalone_method_name_str = format!("{}_{}", enum_ident.to_string().to_case(Case::Snake), method_ident.to_string()); - let standalone_method_ident = syn::Ident::new(&standalone_method_name_str, variant_ident.span()); + let standalone_method_name_str = format!( "{}_{}", enum_ident.to_string().to_case( Case::Snake ), method_ident ); + let standalone_method_ident = syn::Ident::new( &standalone_method_name_str, variant_ident.span() ); let generated_standalone = quote! { diff --git a/module/core/former_meta/src/derive_former/former_enum/unit_variant_handler.rs b/module/core/former_meta/src/derive_former/former_enum/unit_variant_handler.rs index 2996959db8..51b28e7755 100644 --- a/module/core/former_meta/src/derive_former/former_enum/unit_variant_handler.rs +++ b/module/core/former_meta/src/derive_former/former_enum/unit_variant_handler.rs @@ -6,8 +6,7 @@ use macro_tools:: generic_params::GenericsRef, // For enhanced generics handling ident, // For proposed ident::new_ident_from_cased_str qt, // For qt! macro, if preferred over quote::quote! - syn, - quote::quote_spanned, // Keep for specific span control if needed, or replace with qt! + syn }; use super::EnumVariantHandlerContext; use convert_case::{ Case, Casing }; // Keep for Case::Snake @@ -23,12 +22,12 @@ pub( crate ) fn handle( ctx : &mut EnumVariantHandlerContext< '_ > ) -> Result< // we might need to iterate attributes here to find the span, or use a broader span. // For this refactoring, we'll assume `FieldAttributes` can provide a span for `subform_scalar` if present. // If not, `ctx.variant.span()` is a fallback. - if let Some( attr_property ) = &ctx.variant_attrs.subform_scalar // Assuming FieldAttributes stores it as Option + if let Some( _attr_property ) = &ctx.variant_attrs.subform_scalar // Assuming FieldAttributes stores it as Option { // If AttributeProperty has a span() method or field: // return diag::return_syn_err!( attr_property.span(), "Attribute `subform_scalar` is not applicable to unit variants" ); // Otherwise, using variant span as a fallback: - return diag::return_syn_err!( ctx.variant.span(), "Attribute `subform_scalar` is not applicable to unit variants" ); + diag::return_syn_err!( ctx.variant.span(), "Attribute `subform_scalar` is not applicable to unit variants" ); } let variant_ident = &ctx.variant.ident; @@ -51,7 +50,7 @@ pub( crate ) fn handle( ctx : &mut EnumVariantHandlerContext< '_ > ) -> Result< // Prepare generics using the proposed (conceptual) GenericsRef enhancements // These will also fail to compile until Increment 6. - let generics_ref = GenericsRef::new_borrowed( &ctx.generics ); + let generics_ref = GenericsRef::new_borrowed( ctx.generics ); let fn_signature_generics = generics_ref.impl_generics_tokens_if_any()?; let return_type_generics = generics_ref.ty_generics_tokens_if_any()?; let enum_path_for_construction = generics_ref.type_path_tokens_if_any( enum_name )?; diff --git a/module/core/former_meta/src/derive_former/struct_attrs.rs b/module/core/former_meta/src/derive_former/struct_attrs.rs index dee59783e3..846968b2cf 100644 --- a/module/core/former_meta/src/derive_former/struct_attrs.rs +++ b/module/core/former_meta/src/derive_former/struct_attrs.rs @@ -16,7 +16,7 @@ use macro_tools:: use component_model_types::{ Assign, OptionExt }; /// Represents the attributes of a struct, including storage fields, mutator, perform, and standalone constructor attributes. // <<< Updated doc -#[ derive( Debug ) ] // Removed Default from derive +#[ derive( Debug, Default ) ] // Removed Default from derive pub struct ItemAttributes { /// Optional attribute for storage-specific fields. @@ -31,24 +31,12 @@ pub struct ItemAttributes pub debug : AttributePropertyDebug, // Added debug field } -// Default impl needs to include the new debug field -impl Default for ItemAttributes { - fn default() -> Self { - Self { - storage_fields: Default::default(), - mutator: Default::default(), - perform: Default::default(), - standalone_constructors: Default::default(), - debug: Default::default(), // Initialize debug - } - } -} impl ItemAttributes { /// Parses attributes from an iterator. - /// This function now expects to find #[former(debug, standalone_constructors, ...)] - /// and also handles top-level #[storage_fields(...)], #[mutator(...)], #[perform(...)] + /// This function now expects to find #[former(debug, `standalone_constructors`, ...)] + /// and also handles top-level #[`storage_fields`(...)], #[mutator(...)], #[perform(...)] pub fn from_attrs< 'a >( attrs_iter : impl Iterator< Item = &'a syn::Attribute > ) -> Result< Self > { let mut result = Self::default(); @@ -441,11 +429,11 @@ impl syn::parse::Parse for ItemAttributes { // Initialize fields that are NOT parsed from inside #[former()] here // to their defaults, as this Parse impl is only for former's args. storage_fields: None, - mutator: Default::default(), + mutator: AttributeMutator::default(), perform: None, // These will be overwritten if found - standalone_constructors: Default::default(), - debug: Default::default(), + standalone_constructors: AttributePropertyOptionalSingletone::default(), + debug: AttributePropertyOptionalSingletone::default(), }; while !input.is_empty() { diff --git a/module/core/macro_tools/src/ident.rs b/module/core/macro_tools/src/ident.rs index 3b475f38d4..5a375689ab 100644 --- a/module/core/macro_tools/src/ident.rs +++ b/module/core/macro_tools/src/ident.rs @@ -51,20 +51,25 @@ mod private /// `syn::Ident::new_raw` is used. Otherwise, `syn::Ident::new` is used. /// /// Returns an error if `cased_name_str` is empty or an invalid identifier. + // FIX: Add # Errors documentation section. + /// # Errors + /// + /// This function will return an error in the following cases: + /// - If `cased_name_str` is an empty string. + /// - If `cased_name_str` contains characters that are not valid for a Rust identifier. + /// - If `cased_name_str` would be an invalid identifier (e.g., starts with a number). pub fn new_ident_from_cased_str ( - cased_name_str: &str, - span: proc_macro2::Span, - source_had_raw_prefix: bool - ) -> Result // Use local Result alias + cased_name_str : &str, + span : proc_macro2::Span, + source_had_raw_prefix : bool + ) -> Result< syn::Ident > // Use local Result alias { - if cased_name_str.is_empty() { - return Err(syn::Error::new(span, "Cannot create identifier from empty string")); - } // Comprehensive list of Rust 2021 keywords that are problematic as idents. // Based on https://doc.rust-lang.org/reference/keywords.html - const RUST_KEYWORDS: &[&str] = &[ + const RUST_KEYWORDS: &[ &str ] = + &[ // Strict keywords "as", "break", "const", "continue", "crate", "else", "enum", "extern", "false", "fn", "for", "if", "impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub", @@ -77,30 +82,39 @@ mod private "dyn", "union", ]; - let is_keyword = RUST_KEYWORDS.contains(&cased_name_str); + if cased_name_str.is_empty() + { + return Err( syn::Error::new( span, "Cannot create identifier from empty string" ) ); + } - if source_had_raw_prefix || is_keyword { + let is_keyword = RUST_KEYWORDS.contains( &cased_name_str ); + + if source_had_raw_prefix || is_keyword + { // Validate if the string is permissible for new_raw, even if it's a keyword. // For example, "123" is not a keyword but also not valid for new_raw("123", span). // A simple validation is to check if it would parse if it *weren't* a keyword. // This is tricky because `syn::parse_str` would fail for actual keywords. // Let's rely on `syn::Ident::new_raw` to do its job, but catch obvious non-ident chars. - if cased_name_str.chars().any(|c| !c.is_alphanumeric() && c != '_') { - if !( cased_name_str.starts_with('_') && cased_name_str.chars().skip(1).all(|c| c.is_alphanumeric() || c == '_') ) && cased_name_str != "_" { - return Err(syn::Error::new(span, format!("Invalid characters in identifier string for raw creation: {}", cased_name_str))); - } + if cased_name_str.chars().any( | c | !c.is_alphanumeric() && c != '_' ) && !( cased_name_str.starts_with( '_' ) && cased_name_str.chars().skip( 1 ).all( | c | c.is_alphanumeric() || c == '_' ) ) && cased_name_str != "_" + { + return Err( syn::Error::new( span, format!( "Invalid characters in identifier string for raw creation: {cased_name_str}" ) ) ); } - Ok(syn::Ident::new_raw(cased_name_str, span)) - } else { + Ok( syn::Ident::new_raw( cased_name_str, span ) ) + } + else + { // Not a keyword and source was not raw. Try to create a normal identifier. // syn::Ident::new would panic on keywords, but we've established it's not a keyword. // It will also panic on other invalid idents like "123" or "with space". // To provide a Result, we attempt to parse it. - match syn::parse_str::(cased_name_str) { - Ok(ident) => Ok(ident), - Err(_e) => { + match syn::parse_str::< syn::Ident >( cased_name_str ) + { + Ok( ident ) => Ok( ident ), + Err( _e ) => + { // Construct a new error, because the error from parse_str might not have the right span or context. - Err(syn::Error::new(span, format!("Invalid identifier string: '{}'", cased_name_str))) + Err( syn::Error::new( span, format!( "Invalid identifier string: '{cased_name_str}'" ) ) ) } } } diff --git a/module/core/pth/src/path/absolute_path.rs b/module/core/pth/src/path/absolute_path.rs index dd0af7a665..0fe344ece1 100644 --- a/module/core/pth/src/path/absolute_path.rs +++ b/module/core/pth/src/path/absolute_path.rs @@ -167,7 +167,7 @@ mod private if !is_absolute( &path ) { - return Err( io::Error::new( io::ErrorKind::Other, format!( "Path expected to be absolute, but it's not {path:?}" ) ) ); + return Err( io::Error::other( format!( "Path expected to be absolute, but it's not {}", path.display() ) ) ); } Ok( Self( path ) ) @@ -260,7 +260,7 @@ mod private #[ inline ] fn try_from( src : &'a AbsolutePath ) -> Result< &'a str, Self::Error > { - src.to_str().ok_or_else( || io::Error::new( io::ErrorKind::Other, format!( "Can't convert &PathBuf into &str {src}" ) ) ) + src.to_str().ok_or_else( || io::Error::other( format!( "Can't convert &PathBuf into &str {src}" ) ) ) } } diff --git a/module/core/pth/src/path/canonical_path.rs b/module/core/pth/src/path/canonical_path.rs index b45be827c0..ab1c26a574 100644 --- a/module/core/pth/src/path/canonical_path.rs +++ b/module/core/pth/src/path/canonical_path.rs @@ -229,7 +229,7 @@ mod private .to_str() .ok_or_else ( - move || io::Error::new( io::ErrorKind::Other, format!( "Can't convert &PathBuf into &str {src}" ) ) + move || io::Error::other( format!( "Can't convert &PathBuf into &str {src}" ) ) ) } } diff --git a/module/core/pth/src/path/native_path.rs b/module/core/pth/src/path/native_path.rs index 56a249c457..3546590d7c 100644 --- a/module/core/pth/src/path/native_path.rs +++ b/module/core/pth/src/path/native_path.rs @@ -243,7 +243,7 @@ mod private .to_str() .ok_or_else ( - move || io::Error::new( io::ErrorKind::Other, format!( "Can't convert &PathBuf into &str {src}" ) ) + move || io::Error::other( format!( "Can't convert &PathBuf into &str {src}" ) ) ) } }