diff --git a/Cargo.toml b/Cargo.toml index 2819bbf5ad..4bfc9102a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -112,13 +112,13 @@ default-features = false ## derive [workspace.dependencies.derive_tools] -version = "~0.22.0" +version = "~0.23.0" path = "module/core/derive_tools" default-features = false features = [ "enabled" ] [workspace.dependencies.derive_tools_meta] -version = "~0.21.0" +version = "~0.22.0" path = "module/core/derive_tools_meta" default-features = false features = [ "enabled" ] @@ -146,19 +146,19 @@ path = "module/alias/fundamental_data_type" default-features = false [workspace.dependencies.variadic_from] -version = "~0.17.0" +version = "~0.18.0" path = "module/core/variadic_from" default-features = false features = [ "enabled" ] [workspace.dependencies.clone_dyn] -version = "~0.16.0" +version = "~0.17.0" path = "module/core/clone_dyn" default-features = false features = [ "enabled" ] [workspace.dependencies.clone_dyn_meta] -version = "~0.16.0" +version = "~0.17.0" path = "module/core/clone_dyn_meta" features = [ "enabled" ] @@ -200,7 +200,7 @@ path = "module/core/for_each" default-features = false [workspace.dependencies.former] -version = "~2.0.0" +version = "~2.1.0" path = "module/core/former" default-features = false @@ -210,12 +210,12 @@ version = "=2.0.0" default-features = false [workspace.dependencies.former_meta] -version = "~2.0.0" +version = "~2.1.0" path = "module/core/former_meta" default-features = false [workspace.dependencies.former_types] -version = "~2.1.0" +version = "~2.2.0" path = "module/core/former_types" default-features = false @@ -229,12 +229,12 @@ version = "~0.7.0" path = "module/core/impls_index_meta" [workspace.dependencies.mod_interface] -version = "~0.19.0" +version = "~0.20.0" path = "module/core/mod_interface" default-features = false [workspace.dependencies.mod_interface_meta] -version = "~0.19.0" +version = "~0.20.0" path = "module/core/mod_interface_meta" default-features = false @@ -260,7 +260,7 @@ default-features = false ## macro tools [workspace.dependencies.macro_tools] -version = "~0.26.0" +version = "~0.27.0" path = "module/core/macro_tools" default-features = false @@ -314,7 +314,7 @@ default-features = false ## error [workspace.dependencies.error_tools] -version = "~0.13.0" +version = "~0.14.0" path = "module/core/error_tools" default-features = false @@ -326,7 +326,7 @@ path = "module/alias/werror" ## string tools [workspace.dependencies.strs_tools] -version = "~0.12.0" +version = "~0.13.0" path = "module/core/strs_tools" default-features = false @@ -348,7 +348,7 @@ path = "module/alias/file_tools" default-features = false [workspace.dependencies.proper_path_tools] -version = "~0.5.0" +version = "~0.6.0" path = "module/core/proper_path_tools" default-features = false @@ -356,7 +356,7 @@ default-features = false ## process tools [workspace.dependencies.process_tools] -version = "~0.4.0" +version = "~0.5.0" path = "module/core/process_tools" default-features = false @@ -403,7 +403,7 @@ default-features = false ## ca [workspace.dependencies.wca] -version = "~0.16.0" +version = "~0.17.0" path = "module/move/wca" @@ -417,7 +417,7 @@ path = "module/move/wcensor" ## willbe [workspace.dependencies.willbe] -version = "~0.10.0" +version = "~0.11.0" path = "module/move/willbe" @@ -457,7 +457,7 @@ version = "~0.5.0" path = "module/move/deterministic_rand" [workspace.dependencies.crates_tools] -version = "~0.9.0" +version = "~0.10.0" path = "module/move/crates_tools" diff --git a/Readme.md b/Readme.md index c77bc38422..d372d888da 100644 --- a/Readme.md +++ b/Readme.md @@ -22,9 +22,10 @@ Collection of general purpose tools for solving problems. Fundamentally extend t | [clone_dyn_meta](module/core/clone_dyn_meta) | [![experimental](https://raster.shields.io/static/v1?label=&message=experimental&color=orange)](https://github.com/emersion/stability-badges#experimental) | [![rust-status](https://img.shields.io/github/actions/workflow/status/Wandalen/wTools/module_clone_dyn_meta_push.yml?label=&branch=master)](https://github.com/Wandalen/wTools/actions/workflows/module_clone_dyn_meta_push.yml?query=branch%3Amaster) | [![rust-status](https://img.shields.io/github/actions/workflow/status/Wandalen/wTools/module_clone_dyn_meta_push.yml?label=&branch=alpha)](https://github.com/Wandalen/wTools/actions/workflows/module_clone_dyn_meta_push.yml?query=branch%3Aalpha) | [![docs.rs](https://raster.shields.io/static/v1?label=&message=docs&color=eee)](https://docs.rs/clone_dyn_meta) | | | [derive_tools_meta](module/core/derive_tools_meta) | [![experimental](https://raster.shields.io/static/v1?label=&message=experimental&color=orange)](https://github.com/emersion/stability-badges#experimental) | [![rust-status](https://img.shields.io/github/actions/workflow/status/Wandalen/wTools/module_derive_tools_meta_push.yml?label=&branch=master)](https://github.com/Wandalen/wTools/actions/workflows/module_derive_tools_meta_push.yml?query=branch%3Amaster) | [![rust-status](https://img.shields.io/github/actions/workflow/status/Wandalen/wTools/module_derive_tools_meta_push.yml?label=&branch=alpha)](https://github.com/Wandalen/wTools/actions/workflows/module_derive_tools_meta_push.yml?query=branch%3Aalpha) | [![docs.rs](https://raster.shields.io/static/v1?label=&message=docs&color=eee)](https://docs.rs/derive_tools_meta) | | | [clone_dyn](module/core/clone_dyn) | [![experimental](https://raster.shields.io/static/v1?label=&message=experimental&color=orange)](https://github.com/emersion/stability-badges#experimental) | [![rust-status](https://img.shields.io/github/actions/workflow/status/Wandalen/wTools/module_clone_dyn_push.yml?label=&branch=master)](https://github.com/Wandalen/wTools/actions/workflows/module_clone_dyn_push.yml?query=branch%3Amaster) | [![rust-status](https://img.shields.io/github/actions/workflow/status/Wandalen/wTools/module_clone_dyn_push.yml?label=&branch=alpha)](https://github.com/Wandalen/wTools/actions/workflows/module_clone_dyn_push.yml?query=branch%3Aalpha) | [![docs.rs](https://raster.shields.io/static/v1?label=&message=docs&color=eee)](https://docs.rs/clone_dyn) | [![Open in Gitpod](https://raster.shields.io/static/v1?label=&message=try&color=eee)](https://gitpod.io/#RUN_PATH=.,SAMPLE_FILE=module%2Fcore%2Fclone_dyn%2Fexamples%2Fclone_dyn_trivial.rs,RUN_POSTFIX=--example%20clone_dyn_trivial/https://github.com/Wandalen/wTools) | +| [collection_tools](module/core/collection_tools) | [![experimental](https://raster.shields.io/static/v1?label=&message=experimental&color=orange)](https://github.com/emersion/stability-badges#experimental) | [![rust-status](https://img.shields.io/github/actions/workflow/status/Wandalen/wTools/module_collection_tools_push.yml?label=&branch=master)](https://github.com/Wandalen/wTools/actions/workflows/module_collection_tools_push.yml?query=branch%3Amaster) | [![rust-status](https://img.shields.io/github/actions/workflow/status/Wandalen/wTools/module_collection_tools_push.yml?label=&branch=alpha)](https://github.com/Wandalen/wTools/actions/workflows/module_collection_tools_push.yml?query=branch%3Aalpha) | [![docs.rs](https://raster.shields.io/static/v1?label=&message=docs&color=eee)](https://docs.rs/collection_tools) | [![Open in Gitpod](https://raster.shields.io/static/v1?label=&message=try&color=eee)](https://gitpod.io/#RUN_PATH=.,SAMPLE_FILE=module%2Fcore%2Fcollection_tools%2Fexamples%2Fcollection_tools_trivial.rs,RUN_POSTFIX=--example%20collection_tools_trivial/https://github.com/Wandalen/wTools) | | [variadic_from](module/core/variadic_from) | [![experimental](https://raster.shields.io/static/v1?label=&message=experimental&color=orange)](https://github.com/emersion/stability-badges#experimental) | [![rust-status](https://img.shields.io/github/actions/workflow/status/Wandalen/wTools/module_variadic_from_push.yml?label=&branch=master)](https://github.com/Wandalen/wTools/actions/workflows/module_variadic_from_push.yml?query=branch%3Amaster) | [![rust-status](https://img.shields.io/github/actions/workflow/status/Wandalen/wTools/module_variadic_from_push.yml?label=&branch=alpha)](https://github.com/Wandalen/wTools/actions/workflows/module_variadic_from_push.yml?query=branch%3Aalpha) | [![docs.rs](https://raster.shields.io/static/v1?label=&message=docs&color=eee)](https://docs.rs/variadic_from) | [![Open in Gitpod](https://raster.shields.io/static/v1?label=&message=try&color=eee)](https://gitpod.io/#RUN_PATH=.,SAMPLE_FILE=module%2Fcore%2Fvariadic_from%2Fexamples%2Fvariadic_from_trivial.rs,RUN_POSTFIX=--example%20variadic_from_trivial/https://github.com/Wandalen/wTools) | | [derive_tools](module/core/derive_tools) | [![experimental](https://raster.shields.io/static/v1?label=&message=experimental&color=orange)](https://github.com/emersion/stability-badges#experimental) | [![rust-status](https://img.shields.io/github/actions/workflow/status/Wandalen/wTools/module_derive_tools_push.yml?label=&branch=master)](https://github.com/Wandalen/wTools/actions/workflows/module_derive_tools_push.yml?query=branch%3Amaster) | [![rust-status](https://img.shields.io/github/actions/workflow/status/Wandalen/wTools/module_derive_tools_push.yml?label=&branch=alpha)](https://github.com/Wandalen/wTools/actions/workflows/module_derive_tools_push.yml?query=branch%3Aalpha) | [![docs.rs](https://raster.shields.io/static/v1?label=&message=docs&color=eee)](https://docs.rs/derive_tools) | [![Open in Gitpod](https://raster.shields.io/static/v1?label=&message=try&color=eee)](https://gitpod.io/#RUN_PATH=.,SAMPLE_FILE=module%2Fcore%2Fderive_tools%2Fexamples%2Fderive_tools_trivial.rs,RUN_POSTFIX=--example%20derive_tools_trivial/https://github.com/Wandalen/wTools) | -| [collection_tools](module/core/collection_tools) | [![experimental](https://raster.shields.io/static/v1?label=&message=experimental&color=orange)](https://github.com/emersion/stability-badges#experimental) | [![rust-status](https://img.shields.io/github/actions/workflow/status/Wandalen/wTools/module_collection_tools_push.yml?label=&branch=master)](https://github.com/Wandalen/wTools/actions/workflows/module_collection_tools_push.yml?query=branch%3Amaster) | [![rust-status](https://img.shields.io/github/actions/workflow/status/Wandalen/wTools/module_collection_tools_push.yml?label=&branch=alpha)](https://github.com/Wandalen/wTools/actions/workflows/module_collection_tools_push.yml?query=branch%3Aalpha) | [![docs.rs](https://raster.shields.io/static/v1?label=&message=docs&color=eee)](https://docs.rs/collection_tools) | [![Open in Gitpod](https://raster.shields.io/static/v1?label=&message=try&color=eee)](https://gitpod.io/#RUN_PATH=.,SAMPLE_FILE=module%2Fcore%2Fcollection_tools%2Fexamples%2Fcollection_tools_trivial.rs,RUN_POSTFIX=--example%20collection_tools_trivial/https://github.com/Wandalen/wTools) | +| [former_types](module/core/former_types) | [![experimental](https://raster.shields.io/static/v1?label=&message=experimental&color=orange)](https://github.com/emersion/stability-badges#experimental) | [![rust-status](https://img.shields.io/github/actions/workflow/status/Wandalen/wTools/module_former_types_push.yml?label=&branch=master)](https://github.com/Wandalen/wTools/actions/workflows/module_former_types_push.yml?query=branch%3Amaster) | [![rust-status](https://img.shields.io/github/actions/workflow/status/Wandalen/wTools/module_former_types_push.yml?label=&branch=alpha)](https://github.com/Wandalen/wTools/actions/workflows/module_former_types_push.yml?query=branch%3Aalpha) | [![docs.rs](https://raster.shields.io/static/v1?label=&message=docs&color=eee)](https://docs.rs/former_types) | [![Open in Gitpod](https://raster.shields.io/static/v1?label=&message=try&color=eee)](https://gitpod.io/#RUN_PATH=.,SAMPLE_FILE=module%2Fcore%2Fformer_types%2Fexamples%2Fformer_types_trivial.rs,RUN_POSTFIX=--example%20former_types_trivial/https://github.com/Wandalen/wTools) | | [former_meta](module/core/former_meta) | [![experimental](https://raster.shields.io/static/v1?label=&message=experimental&color=orange)](https://github.com/emersion/stability-badges#experimental) | [![rust-status](https://img.shields.io/github/actions/workflow/status/Wandalen/wTools/module_former_meta_push.yml?label=&branch=master)](https://github.com/Wandalen/wTools/actions/workflows/module_former_meta_push.yml?query=branch%3Amaster) | [![rust-status](https://img.shields.io/github/actions/workflow/status/Wandalen/wTools/module_former_meta_push.yml?label=&branch=alpha)](https://github.com/Wandalen/wTools/actions/workflows/module_former_meta_push.yml?query=branch%3Aalpha) | [![docs.rs](https://raster.shields.io/static/v1?label=&message=docs&color=eee)](https://docs.rs/former_meta) | | | [impls_index_meta](module/core/impls_index_meta) | [![experimental](https://raster.shields.io/static/v1?label=&message=experimental&color=orange)](https://github.com/emersion/stability-badges#experimental) | [![rust-status](https://img.shields.io/github/actions/workflow/status/Wandalen/wTools/module_impls_index_meta_push.yml?label=&branch=master)](https://github.com/Wandalen/wTools/actions/workflows/module_impls_index_meta_push.yml?query=branch%3Amaster) | [![rust-status](https://img.shields.io/github/actions/workflow/status/Wandalen/wTools/module_impls_index_meta_push.yml?label=&branch=alpha)](https://github.com/Wandalen/wTools/actions/workflows/module_impls_index_meta_push.yml?query=branch%3Aalpha) | [![docs.rs](https://raster.shields.io/static/v1?label=&message=docs&color=eee)](https://docs.rs/impls_index_meta) | | | [mod_interface_meta](module/core/mod_interface_meta) | [![experimental](https://raster.shields.io/static/v1?label=&message=experimental&color=orange)](https://github.com/emersion/stability-badges#experimental) | [![rust-status](https://img.shields.io/github/actions/workflow/status/Wandalen/wTools/module_mod_interface_meta_push.yml?label=&branch=master)](https://github.com/Wandalen/wTools/actions/workflows/module_mod_interface_meta_push.yml?query=branch%3Amaster) | [![rust-status](https://img.shields.io/github/actions/workflow/status/Wandalen/wTools/module_mod_interface_meta_push.yml?label=&branch=alpha)](https://github.com/Wandalen/wTools/actions/workflows/module_mod_interface_meta_push.yml?query=branch%3Aalpha) | [![docs.rs](https://raster.shields.io/static/v1?label=&message=docs&color=eee)](https://docs.rs/mod_interface_meta) | | diff --git a/debug b/debug new file mode 100644 index 0000000000..c233ba713f --- /dev/null +++ b/debug @@ -0,0 +1,3 @@ +[program_tools_v1 0b9968c19] former : property hint - + 1 file changed, 1 insertion(+) +Already up to date. diff --git a/module/core/clone_dyn/Cargo.toml b/module/core/clone_dyn/Cargo.toml index a409934586..f71ec38feb 100644 --- a/module/core/clone_dyn/Cargo.toml +++ b/module/core/clone_dyn/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clone_dyn" -version = "0.16.0" +version = "0.17.0" edition = "2021" authors = [ "Kostiantyn Wandalen ", diff --git a/module/core/clone_dyn_meta/Cargo.toml b/module/core/clone_dyn_meta/Cargo.toml index 0cc0f336f6..e6d9bf304e 100644 --- a/module/core/clone_dyn_meta/Cargo.toml +++ b/module/core/clone_dyn_meta/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clone_dyn_meta" -version = "0.16.0" +version = "0.17.0" edition = "2021" authors = [ "Kostiantyn Wandalen ", diff --git a/module/core/derive_tools/Cargo.toml b/module/core/derive_tools/Cargo.toml index 3f33bc2770..d54788975c 100644 --- a/module/core/derive_tools/Cargo.toml +++ b/module/core/derive_tools/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "derive_tools" -version = "0.22.0" +version = "0.23.0" edition = "2021" authors = [ "Kostiantyn Wandalen ", diff --git a/module/core/derive_tools/tests/inc/from_inner_variants_collisions.rs b/module/core/derive_tools/tests/inc/from_inner_variants_collisions.rs index e04334e1fc..d7bb05fa83 100644 --- a/module/core/derive_tools/tests/inc/from_inner_variants_collisions.rs +++ b/module/core/derive_tools/tests/inc/from_inner_variants_collisions.rs @@ -25,15 +25,3 @@ pub enum GetData // == end of generated include!( "./only_test/from_inner_variants.rs" ); - -// xxx2 : implement attribute `#[ from( off ) ]` -// -// #[ derive( Debug, PartialEq, From ) ] -// // #[ debug ] -// pub enum GetData< 'a, T > -// where -// T : ToString + ?Sized, -// { -// FromBin( &'static [ u8 ] ), -// FromT( &'a T ), -// } diff --git a/module/core/derive_tools/tests/inc/from_inner_variants_duplicates.rs b/module/core/derive_tools/tests/inc/from_inner_variants_duplicates_all_off.rs similarity index 59% rename from module/core/derive_tools/tests/inc/from_inner_variants_duplicates.rs rename to module/core/derive_tools/tests/inc/from_inner_variants_duplicates_all_off.rs index 4b0488aecb..8d352850ff 100644 --- a/module/core/derive_tools/tests/inc/from_inner_variants_duplicates.rs +++ b/module/core/derive_tools/tests/inc/from_inner_variants_duplicates_all_off.rs @@ -8,9 +8,13 @@ pub enum GetData { Nothing, Nothing2, + #[ from( off ) ] FromString( String ), + #[ from( off ) ] FromString2( String ), + #[ from( off ) ] FromPair( String, String ), + #[ from( off ) ] FromPair2( String, String ), FromBin( &'static [ u8 ] ), Nothing3, @@ -38,20 +42,4 @@ impl From< ( String, String ) > for GetData // == end of generated -#[ test ] -fn variant_from() -{ - - let got : GetData = From::from( &b"abc"[ .. ] ); - let exp = GetData::FromBin( b"abc" ); - a_id!( got, exp ); - - let got : GetData = From::from( "abc".to_string() ); - let exp = GetData::FromString2( "abc".to_string() ); - a_id!( got, exp ); - - let got : GetData = From::from( ( "a".to_string(), "b".to_string() ) ); - let exp = GetData::FromPair2( "a".to_string(), "b".to_string() ); - a_id!( got, exp ); - -} +include!( "./only_test/from_inner_variants_duplicates.rs" ); diff --git a/module/core/derive_tools/tests/inc/from_inner_variants_duplicates_some_off.rs b/module/core/derive_tools/tests/inc/from_inner_variants_duplicates_some_off.rs new file mode 100644 index 0000000000..1fa60cb598 --- /dev/null +++ b/module/core/derive_tools/tests/inc/from_inner_variants_duplicates_some_off.rs @@ -0,0 +1,25 @@ +#![ allow( dead_code ) ] +#[ allow( unused_imports ) ] +use super::*; + +#[ derive( Debug, PartialEq, the_module::From ) ] +// #[ debug ] +pub enum GetData +{ + Nothing, + Nothing2, + #[ from( off ) ] + FromString( String ), + FromString2( String ), + #[ from( off ) ] + FromPair( String, String ), + FromPair2( String, String ), + FromBin( &'static [ u8 ] ), + Nothing3, +} + +// == begin of generated + +// == end of generated + +include!( "./only_test/from_inner_variants_duplicates.rs" ); diff --git a/module/core/derive_tools/tests/inc/from_inner_variants_duplicates_some_off_default_off.rs b/module/core/derive_tools/tests/inc/from_inner_variants_duplicates_some_off_default_off.rs new file mode 100644 index 0000000000..9d60a25204 --- /dev/null +++ b/module/core/derive_tools/tests/inc/from_inner_variants_duplicates_some_off_default_off.rs @@ -0,0 +1,27 @@ +#![ allow( dead_code ) ] +#[ allow( unused_imports ) ] +use super::*; + +#[ derive( Debug, PartialEq, the_module::From ) ] +#[ from( off ) ] +// #[ debug ] +pub enum GetData +{ + Nothing, + Nothing2, + FromString( String ), + #[ from( on ) ] + // #[ from( debug ) ] + FromString2( String ), + FromPair( String, String ), + #[ from( on ) ] + FromPair2( String, String ), + #[ from( on ) ] + FromBin( &'static [ u8 ] ), + Nothing3, +} + +// == begin of generated +// == end of generated + +include!( "./only_test/from_inner_variants_duplicates.rs" ); diff --git a/module/core/derive_tools/tests/inc/mod.rs b/module/core/derive_tools/tests/inc/mod.rs index 382e7b7ff2..779ae76708 100644 --- a/module/core/derive_tools/tests/inc/mod.rs +++ b/module/core/derive_tools/tests/inc/mod.rs @@ -68,8 +68,14 @@ mod from_inner_multiple_test; mod from_inner_variants_manual; #[ cfg( feature = "derive_from" ) ] mod from_inner_variants_derive; + +#[ cfg( feature = "derive_from" ) ] +mod from_inner_variants_duplicates_all_off; #[ cfg( feature = "derive_from" ) ] -mod from_inner_variants_duplicates; +mod from_inner_variants_duplicates_some_off; +#[ cfg( feature = "derive_from" ) ] +mod from_inner_variants_duplicates_some_off_default_off; + #[ cfg( feature = "derive_from" ) ] mod from_inner_variants_generics; #[ cfg( feature = "derive_from" ) ] @@ -92,5 +98,3 @@ mod inner_from_multiple_named_test; mod inner_from_unit_test; #[ cfg( feature = "derive_inner_from" ) ] mod inner_from_multiple_test; - -// xxx diff --git a/module/core/derive_tools/tests/inc/only_test/from_inner_variants_duplicates.rs b/module/core/derive_tools/tests/inc/only_test/from_inner_variants_duplicates.rs new file mode 100644 index 0000000000..9b126ff42e --- /dev/null +++ b/module/core/derive_tools/tests/inc/only_test/from_inner_variants_duplicates.rs @@ -0,0 +1,20 @@ +#[ allow( unused_imports ) ] +use super::*; + +#[ test ] +fn variant_from_duplicates() +{ + + let got : GetData = From::from( &b"abc"[ .. ] ); + let exp = GetData::FromBin( b"abc" ); + a_id!( got, exp ); + + let got : GetData = From::from( "abc".to_string() ); + let exp = GetData::FromString2( "abc".to_string() ); + a_id!( got, exp ); + + let got : GetData = From::from( ( "a".to_string(), "b".to_string() ) ); + let exp = GetData::FromPair2( "a".to_string(), "b".to_string() ); + a_id!( got, exp ); + +} diff --git a/module/core/derive_tools_meta/Cargo.toml b/module/core/derive_tools_meta/Cargo.toml index a229e5c66d..a266fd1ee6 100644 --- a/module/core/derive_tools_meta/Cargo.toml +++ b/module/core/derive_tools_meta/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "derive_tools_meta" -version = "0.21.0" +version = "0.22.0" edition = "2021" authors = [ "Kostiantyn Wandalen ", @@ -63,7 +63,10 @@ derive_variadic_from = [] [dependencies] macro_tools = { workspace = true, features = [ "full" ] } iter_tools = { workspace = true, features = [ "full" ] } -# xxx : qqq : for Petro : optimize features set +former_types = { workspace = true, features = [ "enabled", "types_component_assign" ] } +const_format = { version = "0.2.32" } + +# qqq : optimize features set [dev-dependencies] test_tools = { workspace = true } diff --git a/module/core/derive_tools_meta/src/derive/as_ref.rs b/module/core/derive_tools_meta/src/derive/as_ref.rs index bf5676839d..dba4eacacf 100644 --- a/module/core/derive_tools_meta/src/derive/as_ref.rs +++ b/module/core/derive_tools_meta/src/derive/as_ref.rs @@ -9,7 +9,6 @@ pub fn as_ref( input : proc_macro::TokenStream ) -> Result< proc_macro2::TokenSt let original_input = input.clone(); let parsed = syn::parse::< syn::ItemStruct >( input )?; let has_debug = attr::has_debug( parsed.attrs.iter() )?; - let field_type = item_struct::first_field_type( &parsed )?; let item_name = &parsed.ident; diff --git a/module/core/derive_tools_meta/src/derive/from.rs b/module/core/derive_tools_meta/src/derive/from.rs index e3f330d149..d05b416235 100644 --- a/module/core/derive_tools_meta/src/derive/from.rs +++ b/module/core/derive_tools_meta/src/derive/from.rs @@ -1,7 +1,18 @@ use super::*; -use macro_tools::{ attr, diag, generic_params, item_struct, struct_like::StructLike, Result }; - -// xxx2 : get complete From for enums +use macro_tools:: +{ + attr, + diag, + generic_params, + item_struct, + struct_like::StructLike, + Result, +}; + +mod field_attributes; +use field_attributes::*; +mod item_attributes; +use item_attributes::*; // @@ -12,6 +23,7 @@ pub fn from( input : proc_macro::TokenStream ) -> Result< proc_macro2::TokenStre let original_input = input.clone(); let parsed = syn::parse::< StructLike >( input )?; let has_debug = attr::has_debug( parsed.attrs().iter() )?; + let item_attrs = ItemAttributes::from_attrs( parsed.attrs().iter() )?; let item_name = &parsed.ident(); let ( _generics_with_defaults, generics_impl, generics_ty, generics_where ) @@ -42,7 +54,7 @@ pub fn from( input : proc_macro::TokenStream ) -> Result< proc_macro2::TokenStre &generics_impl, &generics_ty, &generics_where, - field_names.next().unwrap(), // xxx : ? + field_names.next().unwrap(), &field_types.next().unwrap(), ), ( 1, None ) => @@ -88,24 +100,31 @@ pub fn from( input : proc_macro::TokenStream ) -> Result< proc_macro2::TokenStre .or_insert( 1 ); }); - let variants = item.variants.iter().map( | variant | + let variants_result : Result< Vec< proc_macro2::TokenStream > > = item.variants.iter().map( | variant | { - if map[ &variant.fields.to_token_stream().to_string() ] <= 1 + // don't do automatic off + // if map[ & variant.fields.to_token_stream().to_string() ] <= 1 + if true { variant_generate ( item_name, + &item_attrs, &generics_impl, &generics_ty, &generics_where, variant, + &original_input, ) } else { - qt!{} + Ok( qt!{} ) } - }); + }).collect(); + + let variants = variants_result?; + qt! { #( #variants )* @@ -123,61 +142,29 @@ pub fn from( input : proc_macro::TokenStream ) -> Result< proc_macro2::TokenStre } // qqq : document, add example of generated code -fn variant_generate +fn generate_unit ( item_name : &syn::Ident, generics_impl : &syn::punctuated::Punctuated< syn::GenericParam, syn::token::Comma >, generics_ty : &syn::punctuated::Punctuated< syn::GenericParam, syn::token::Comma >, generics_where: &syn::punctuated::Punctuated< syn::WherePredicate, syn::token::Comma >, - variant : &syn::Variant, ) -> proc_macro2::TokenStream { - let variant_name = &variant.ident; - let fields = &variant.fields; - - if fields.len() <= 0 - { - return qt!{} - } - - let ( args, use_src ) = if fields.len() == 1 - { - let field = fields.iter().next().unwrap(); - ( - qt!{ #field }, - qt!{ src }, - ) - } - else - { - let src_i = ( 0..fields.len() ).map( | e | - { - let i = syn::Index::from( e ); - qt!{ src.#i, } - }); - ( - qt!{ #fields }, - qt!{ #( #src_i )* }, - // qt!{ src.0, src.1 }, - ) - }; - qt! { - #[ automatically_derived ] - impl< #generics_impl > From< #args > for #item_name< #generics_ty > + // impl From< () > for UnitStruct + impl< #generics_impl > From< () > for #item_name< #generics_ty > where #generics_where { - #[ inline ] - fn from( src : #args ) -> Self + #[ inline( always ) ] + fn from( src : () ) -> Self { - Self::#variant_name( #use_src ) + Self } } } - } // qqq : document, add example of generated code @@ -242,7 +229,7 @@ fn generate_from_single_field } } -// qqq : for Petro : document, add example of generated code +// qqq : document, add example of generated code fn generate_from_multiple_fields_named< 'a > ( item_name : &syn::Ident, @@ -324,204 +311,102 @@ fn generate_from_multiple_fields< 'a > } } - // qqq : document, add example of generated code -fn generate_unit +fn variant_generate ( item_name : &syn::Ident, + item_attrs : &ItemAttributes, generics_impl : &syn::punctuated::Punctuated< syn::GenericParam, syn::token::Comma >, generics_ty : &syn::punctuated::Punctuated< syn::GenericParam, syn::token::Comma >, generics_where: &syn::punctuated::Punctuated< syn::WherePredicate, syn::token::Comma >, + variant : &syn::Variant, + original_input : &proc_macro::TokenStream, ) --> proc_macro2::TokenStream +-> Result< proc_macro2::TokenStream > { - qt! + let variant_name = &variant.ident; + let fields = &variant.fields; + let attrs = FieldAttributes::from_attrs( variant.attrs.iter() )?; + + if !attrs.config.enabled.value( item_attrs.config.enabled.value( true ) ) { - // impl From< () > for UnitStruct - impl< #generics_impl > From< () > for #item_name< #generics_ty > - where - #generics_where - { - #[ inline( always ) ] - fn from( src : () ) -> Self - { - Self - } - } + return Ok( qt!{} ) } -} - -// xxx2 : get completed - -/// -/// Attributes of a field / variant -/// -pub struct FieldAttributes -{ - pub from : Option< AttributeFrom >, -} - -impl FieldAttributes -{ - - pub fn from_attrs< 'a >( attrs : impl Iterator< Item = &'a syn::Attribute > ) -> Result< Self > + if fields.len() <= 0 { - let mut from : Option< AttributeFrom > = None; - - for attr in attrs - { - let key_ident = attr.path().get_ident() - .ok_or_else( || syn_err!( attr, "Expects an attribute of format #[ attribute( key1 = val1, key2 = val2 ) ], but got:\n {}", qt!{ #attr } ) )?; - let key_str = format!( "{}", key_ident ); - - if attr::is_standard( &key_str ) - { - continue; - } - - // qqq : qqq for Anton : xxx : refactor field_attrs::FieldAttributes::from_attrs to make it similar to this function - match key_str.as_ref() - { - AttributeFrom::KEYWORD => - { - from.replace( AttributeFrom::from_meta( attr )? ); - } - "debug" => - { - } - _ => - { - return Err( syn_err!( attr, "Known field attirbutes are : `from`, `debug`.\nUnknown structure attribute : {}", qt!{ #attr } ) ); - } - } - } - - Ok( FieldAttributes { from } ) + return Ok( qt!{} ) } -} - - -/// -/// Attribute to hold parameters of forming for a specific field or variant. -/// For example to avoid code From generation for it. -/// -/// `#[ from( off, hint : true ) ]` -/// - -#[ derive( Default ) ] -pub struct AttributeFrom -{ - /// Specifies whether we should generate From implementation for the field. - /// Can be altered using `on` and `off` attributes - pub enabled : Option< bool >, - /// Specifies whether to provide a sketch of generated From or not. - /// Defaults to `false`, which means no hint is provided unless explicitly requested. - pub hint : bool, -} - -impl AttributeFrom -{ - - const KEYWORD : &'static str = "from"; - - pub fn from_meta( attr : &syn::Attribute ) -> Result< Self > + let ( args, use_src ) = if fields.len() == 1 { - match attr.meta - { - syn::Meta::List( ref meta_list ) => - { - return syn::parse2::< AttributeFrom >( meta_list.tokens.clone() ); - }, - syn::Meta::Path( ref _path ) => - { - return Ok( Default::default() ) - }, - _ => return_syn_err!( attr, "Expects an attribute of format #[ from( off ) ] -.\nGot: {}", qt!{ #attr } ), - } + let field = fields.iter().next().unwrap(); + ( + qt!{ #field }, + qt!{ src }, + ) } + else + { + let src_i = ( 0..fields.len() ).map( | e | + { + let i = syn::Index::from( e ); + qt!{ src.#i, } + }); + ( + qt!{ #fields }, + qt!{ #( #src_i )* }, + // qt!{ src.0, src.1 }, + ) + }; -} - -impl syn::parse::Parse for AttributeFrom -{ - fn parse( input : syn::parse::ParseStream< '_ > ) -> syn::Result< Self > + // qqq : make `debug` working for all branches + if attrs.config.debug.value( false ) { - let mut off : bool = false; - let mut on : bool = false; - let mut hint = false; + let debug = format! + ( + r#" +#[ automatically_derived ] +impl< {0} > From< {args} > for {item_name}< {1} > +where + {2} +{{ + #[ inline ] + fn from( src : {args} ) -> Self + {{ + Self::{variant_name}( {use_src} ) + }} +}} + "#, + format!( "{}", qt!{ #generics_impl } ), + format!( "{}", qt!{ #generics_ty } ), + format!( "{}", qt!{ #generics_where } ), + ); + let about = format! + ( +r#"derive : From +item : {item_name} +field : {variant_name}"#, + ); + diag::report_print( about, original_input, debug ); + } - while !input.is_empty() + Ok + ( + qt! { - let lookahead = input.lookahead1(); - if lookahead.peek( syn::Ident ) + #[ automatically_derived ] + impl< #generics_impl > From< #args > for #item_name< #generics_ty > + where + #generics_where { - let ident : syn::Ident = input.parse()?; - // xxx : qqq for Anton : use match here and for all attributes -- done - match ident.to_string().as_str() + #[ inline ] + fn from( src : #args ) -> Self { - "off" => - { - input.parse::< syn::Token![ = ] >()?; - let value : syn::LitBool = input.parse()?; - off = value.value(); - }, - "on" => - { - input.parse::< syn::Token![ = ] >()?; - let value : syn::LitBool = input.parse()?; - on = value.value(); - } - "hint" => - { - input.parse::< syn::Token![ = ] >()?; - let value : syn::LitBool = input.parse()?; - hint = value.value; - } - _ => - { - return Err( syn::Error::new_spanned( &ident, format!( "Unexpected identifier '{}'. Expected 'on', 'off', or 'hint'. For example: `#[ from( off, hint : true ) ]`", ident ) ) ); - } + Self::#variant_name( #use_src ) } } - else - { - return Err( syn::Error::new( input.span(), "Unexpected identifier '{}'. Expected 'on', 'off', or 'hint'. For example: `#[ from( off, hint : true ) ]`" ) ); - } - - } - - // xxx : move on / off logic into a helper - - let mut enabled : Option< bool > = None; - - if on && off - { - // return Err( syn_err!( input, "`on` and `off` are mutually exclusive .\nIllegal attribute usage : {}", qt!{ #input } ) ) - return Err( syn::Error::new( input.span(), "`on` and `off` are mutually exclusive .\nIllegal attribute usage" ) ); - // xxx : test - } - - if !on && !off - { - enabled = None; - } - else if on - { - enabled = Some( true ) - } - else if off - { - enabled = Some( false ) } + ) - // Optional comma handling - if input.peek( syn::Token![ , ] ) - { - input.parse::< syn::Token![ , ] >()?; - } - Ok( Self { enabled, hint } ) - } } diff --git a/module/core/derive_tools_meta/src/derive/from/field_attributes.rs b/module/core/derive_tools_meta/src/derive/from/field_attributes.rs new file mode 100644 index 0000000000..8ff1e9f56f --- /dev/null +++ b/module/core/derive_tools_meta/src/derive/from/field_attributes.rs @@ -0,0 +1,252 @@ +use super::*; +use macro_tools:: +{ + Result, + AttributeComponent, + AttributePropertyComponent, + AttributePropertyOptionalSingletone, +}; + +use former_types::Assign; + +/// +/// Attributes of a field / variant +/// + +/// Represents the attributes of a struct. Aggregates all its attributes. +#[ derive( Debug, Default ) ] +pub struct FieldAttributes +{ + /// Attribute for customizing generated code. + pub config : FieldAttributeConfig, +} + +impl FieldAttributes +{ + + pub fn from_attrs< 'a >( attrs : impl Iterator< Item = &'a syn::Attribute > ) -> Result< Self > + { + let mut result = Self::default(); + + let error = | attr : &syn::Attribute | -> syn::Error + { + let known_attributes = const_format::concatcp! + ( + "Known attirbutes are : ", + "debug", + ", ", FieldAttributeConfig::KEYWORD, + ".", + ); + syn_err! + ( + attr, + "Expects an attribute of format '#[ attribute( key1 = val1, key2 = val2 ) ]'\n {known_attributes}\n But got: '{}'", + qt!{ #attr } + ) + }; + + for attr in attrs + { + + let key_ident = attr.path().get_ident().ok_or_else( || error( attr ) )?; + let key_str = format!( "{}", key_ident ); + + // attributes does not have to be known + // if attr::is_standard( &key_str ) + // { + // continue; + // } + + match key_str.as_ref() + { + FieldAttributeConfig::KEYWORD => result.assign( FieldAttributeConfig::from_meta( attr )? ), + "debug" => {}, + _ => {}, + // _ => return Err( error( attr ) ), + } + } + + Ok( result ) + } + +} + +/// +/// Attribute to hold parameters of forming for a specific field or variant. +/// For example to avoid code From generation for it. +/// +/// `#[ from( on ) ]` +/// + +#[ derive( Debug, Default ) ] +pub struct FieldAttributeConfig +{ + /// Specifies whether we should generate From implementation for the field. + /// Can be altered using `on` and `off` attributes + pub enabled : AttributePropertyEnabled, + /// Specifies whether to print a sketch of generated `From` or not. + /// Defaults to `false`, which means no code is printed unless explicitly requested. + pub debug : AttributePropertyDebug, + // qqq : apply debug properties to all brenches, not only enums +} + +impl AttributeComponent for FieldAttributeConfig +{ + const KEYWORD : &'static str = "from"; + + fn from_meta( attr : &syn::Attribute ) -> Result< Self > + { + match attr.meta + { + syn::Meta::List( ref meta_list ) => + { + return syn::parse2::< FieldAttributeConfig >( meta_list.tokens.clone() ); + }, + syn::Meta::Path( ref _path ) => + { + return Ok( Default::default() ) + }, + _ => return_syn_err!( attr, "Expects an attribute of format `#[ from( on ) ]`. \nGot: {}", qt!{ #attr } ), + } + } + +} + +impl< IntoT > Assign< FieldAttributeConfig, IntoT > for FieldAttributes +where + IntoT : Into< FieldAttributeConfig >, +{ + #[ inline( always ) ] + fn assign( &mut self, component : IntoT ) + { + self.config.assign( component.into() ); + } +} + +impl< IntoT > Assign< FieldAttributeConfig, IntoT > for FieldAttributeConfig +where + IntoT : Into< FieldAttributeConfig >, +{ + #[ inline( always ) ] + fn assign( &mut self, component : IntoT ) + { + let component = component.into(); + self.enabled.assign( component.enabled ); + self.debug.assign( component.debug ); + } +} + +impl< IntoT > Assign< AttributePropertyEnabled, IntoT > for FieldAttributeConfig +where + IntoT : Into< AttributePropertyEnabled >, +{ + #[ inline( always ) ] + fn assign( &mut self, component : IntoT ) + { + self.enabled = component.into(); + } +} + +impl< IntoT > Assign< AttributePropertyDebug, IntoT > for FieldAttributeConfig +where + IntoT : Into< AttributePropertyDebug >, +{ + #[ inline( always ) ] + fn assign( &mut self, component : IntoT ) + { + self.debug = component.into(); + } +} + +impl syn::parse::Parse for FieldAttributeConfig +{ + fn parse( input : syn::parse::ParseStream< '_ > ) -> syn::Result< Self > + { + let mut result = Self::default(); + + let error = | ident : &syn::Ident | -> syn::Error + { + let known = const_format::concatcp! + ( + "Known entries of attribute ", FieldAttributeConfig::KEYWORD, " are : ", + AttributePropertyDebug::KEYWORD, + ", ", EnabledMarker::KEYWORD_ON, + ", ", EnabledMarker::KEYWORD_OFF, + ".", + ); + syn_err! + ( + ident, + r#"Expects an attribute of format '#[ from( on ) ]' + {known} + But got: '{}' +"#, + qt!{ #ident } + ) + }; + + while !input.is_empty() + { + let lookahead = input.lookahead1(); + if lookahead.peek( syn::Ident ) + { + let ident : syn::Ident = input.parse()?; + match ident.to_string().as_str() + { + AttributePropertyDebug::KEYWORD => result.assign( AttributePropertyDebug::from( true ) ), + EnabledMarker::KEYWORD_ON => result.assign( AttributePropertyEnabled::from( true ) ), + EnabledMarker::KEYWORD_OFF => result.assign( AttributePropertyEnabled::from( false ) ), + _ => return Err( error( &ident ) ), + } + } + else + { + return Err( lookahead.error() ); + } + + // Optional comma handling + if input.peek( syn::Token![ , ] ) + { + input.parse::< syn::Token![ , ] >()?; + } + } + + Ok( result ) + } +} + +// == attribute properties + +/// Marker type for attribute property to specify whether to provide a generated code as a hint. +/// Defaults to `false`, which means no debug is provided unless explicitly requested. +#[ derive( Debug, Default, Clone, Copy ) ] +pub struct AttributePropertyDebugMarker; + +impl AttributePropertyComponent for AttributePropertyDebugMarker +{ + const KEYWORD : &'static str = "debug"; +} + +/// Specifies whether to provide a generated code as a hint. +/// Defaults to `false`, which means no debug is provided unless explicitly requested. +pub type AttributePropertyDebug = AttributePropertyOptionalSingletone< AttributePropertyDebugMarker >; + +// = + +/// Marker type for attribute property to indicates whether `From` implementation for fields/variants should be generated. +#[ derive( Debug, Default, Clone, Copy ) ] +pub struct EnabledMarker; + +impl EnabledMarker +{ + /// Keywords for parsing this attribute property. + pub const KEYWORD_OFF : &'static str = "off"; + /// Keywords for parsing this attribute property. + pub const KEYWORD_ON : &'static str = "on"; +} + +/// Specifies whether `From` implementation for fields/variants should be generated. +/// Can be altered using `on` and `off` attributes. But default it's `on`. +pub type AttributePropertyEnabled = AttributePropertyOptionalSingletone< EnabledMarker >; + +// == diff --git a/module/core/derive_tools_meta/src/derive/from/item_attributes.rs b/module/core/derive_tools_meta/src/derive/from/item_attributes.rs new file mode 100644 index 0000000000..78cc32f2d4 --- /dev/null +++ b/module/core/derive_tools_meta/src/derive/from/item_attributes.rs @@ -0,0 +1,201 @@ +use super::*; +use macro_tools:: +{ + Result, + AttributeComponent, +}; + +use former_types::Assign; + +/// +/// Attributes of the whole tiem +/// + +/// Represents the attributes of a struct. Aggregates all its attributes. +#[ derive( Debug, Default ) ] +pub struct ItemAttributes +{ + /// Attribute for customizing generated code. + pub config : ItemAttributeConfig, +} + +impl ItemAttributes +{ + + pub fn from_attrs< 'a >( attrs : impl Iterator< Item = &'a syn::Attribute > ) -> Result< Self > + { + let mut result = Self::default(); + + let error = | attr : &syn::Attribute | -> syn::Error + { + let known_attributes = const_format::concatcp! + ( + "Known attirbutes are : ", + "debug", + ", ", ItemAttributeConfig::KEYWORD, + ".", + ); + syn_err! + ( + attr, + "Expects an attribute of format '#[ attribute( key1 = val1, key2 = val2 ) ]'\n {known_attributes}\n But got: '{}'", + qt!{ #attr } + ) + }; + + for attr in attrs + { + + let key_ident = attr.path().get_ident().ok_or_else( || error( attr ) )?; + let key_str = format!( "{}", key_ident ); + + // attributes does not have to be known + // if attr::is_standard( &key_str ) + // { + // continue; + // } + + match key_str.as_ref() + { + ItemAttributeConfig::KEYWORD => result.assign( ItemAttributeConfig::from_meta( attr )? ), + "debug" => {} + _ => {}, + // _ => return Err( error( attr ) ), + // attributes does not have to be known + } + } + + Ok( result ) + } + +} + +/// +/// Attribute to hold parameters of forming for a specific field or variant. +/// For example to avoid code From generation for it. +/// +/// `#[ from( on ) ]` +/// + +#[ derive( Debug, Default ) ] +pub struct ItemAttributeConfig +{ + /// Specifies whether `From` implementation for fields/variants should be generated by default. + /// Can be altered using `on` and `off` attributes. But default it's `on`. + /// `#[ from( on ) ]` - `From` is generated unless `off` for the field/variant is explicitly specified. + /// `#[ from( off ) ]` - `From` is not generated unless `on` for the field/variant is explicitly specified. + pub enabled : AttributePropertyEnabled, +} + +impl AttributeComponent for ItemAttributeConfig +{ + const KEYWORD : &'static str = "from"; + + fn from_meta( attr : &syn::Attribute ) -> Result< Self > + { + match attr.meta + { + syn::Meta::List( ref meta_list ) => + { + return syn::parse2::< ItemAttributeConfig >( meta_list.tokens.clone() ); + }, + syn::Meta::Path( ref _path ) => + { + return Ok( Default::default() ) + }, + _ => return_syn_err!( attr, "Expects an attribute of format `#[ from( on ) ]`. \nGot: {}", qt!{ #attr } ), + } + } + +} + +impl< IntoT > Assign< ItemAttributeConfig, IntoT > for ItemAttributes +where + IntoT : Into< ItemAttributeConfig >, +{ + #[ inline( always ) ] + fn assign( &mut self, component : IntoT ) + { + self.config.assign( component.into() ); + } +} + +impl< IntoT > Assign< ItemAttributeConfig, IntoT > for ItemAttributeConfig +where + IntoT : Into< ItemAttributeConfig >, +{ + #[ inline( always ) ] + fn assign( &mut self, component : IntoT ) + { + let component = component.into(); + self.enabled.assign( component.enabled ); + } +} + +impl< IntoT > Assign< AttributePropertyEnabled, IntoT > for ItemAttributeConfig +where + IntoT : Into< AttributePropertyEnabled >, +{ + #[ inline( always ) ] + fn assign( &mut self, component : IntoT ) + { + self.enabled = component.into(); + } +} + +impl syn::parse::Parse for ItemAttributeConfig +{ + fn parse( input : syn::parse::ParseStream< '_ > ) -> syn::Result< Self > + { + let mut result = Self::default(); + + let error = | ident : &syn::Ident | -> syn::Error + { + let known = const_format::concatcp! + ( + "Known entries of attribute ", ItemAttributeConfig::KEYWORD, " are : ", + EnabledMarker::KEYWORD_ON, + ", ", EnabledMarker::KEYWORD_OFF, + ".", + ); + syn_err! + ( + ident, + r#"Expects an attribute of format '#[ from( off ) ]' + {known} + But got: '{}' +"#, + qt!{ #ident } + ) + }; + + while !input.is_empty() + { + let lookahead = input.lookahead1(); + if lookahead.peek( syn::Ident ) + { + let ident : syn::Ident = input.parse()?; + match ident.to_string().as_str() + { + EnabledMarker::KEYWORD_ON => result.assign( AttributePropertyEnabled::from( true ) ), + EnabledMarker::KEYWORD_OFF => result.assign( AttributePropertyEnabled::from( false ) ), + _ => return Err( error( &ident ) ), + } + } + else + { + return Err( lookahead.error() ); + } + + // Optional comma handling + if input.peek( syn::Token![ , ] ) + { + input.parse::< syn::Token![ , ] >()?; + } + } + + Ok( result ) + } +} + +// == diff --git a/module/core/derive_tools_meta/src/derive/variadic_from.rs b/module/core/derive_tools_meta/src/derive/variadic_from.rs index 8d178969f8..9c917dc025 100644 --- a/module/core/derive_tools_meta/src/derive/variadic_from.rs +++ b/module/core/derive_tools_meta/src/derive/variadic_from.rs @@ -18,7 +18,6 @@ pub fn variadic_from( input : proc_macro::TokenStream ) -> Result< proc_macro2:: let len = parsed.fields.len(); let from_trait = format_ident!( "From{len}", ); let from_method = format_ident!( "from{len}" ); - // xxx : test for zero fields let ( diff --git a/module/core/error_tools/Cargo.toml b/module/core/error_tools/Cargo.toml index e1398d3d64..1ef5cccee8 100644 --- a/module/core/error_tools/Cargo.toml +++ b/module/core/error_tools/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "error_tools" -version = "0.13.0" +version = "0.14.0" edition = "2021" authors = [ "Kostiantyn Wandalen ", diff --git a/module/core/former/Cargo.toml b/module/core/former/Cargo.toml index 645deff0c3..563b0cc329 100644 --- a/module/core/former/Cargo.toml +++ b/module/core/former/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "former" -version = "2.0.0" +version = "2.1.0" edition = "2021" authors = [ "Kostiantyn Wandalen ", diff --git a/module/core/former/Readme.md b/module/core/former/Readme.md index 56ff1102b5..68c270f3b8 100644 --- a/module/core/former/Readme.md +++ b/module/core/former/Readme.md @@ -539,8 +539,8 @@ But it's also possible to completely override setter and write its own from scra #[ derive( Debug, Former ) ] pub struct StructWithCustomSetters { - // Use `hint = true` to gennerate sketch of setter. - #[ scalar( setter = false, hint = false ) ] + // Use `debug` to gennerate sketch of setter. + #[ scalar( setter = false ) ] word : String, } @@ -812,8 +812,8 @@ The `child` function within `ParentFormer` is a custom subform setter that plays // #[ debug ] pub struct Parent { - // Use `hint = true` to gennerate sketch of setter. - #[ scalar( setter = false, hint = false ) ] + // Use `debug` to gennerate sketch of setter. + #[ scalar( setter = false ) ] children : HashMap< String, Child >, } @@ -907,7 +907,7 @@ their own formers, allowing for detailed configuration within a nested builder p { // The `subform_scalar` attribute is used to specify that the 'child' field has its own former // and can be individually configured via a subform setter. This is not a collection but a single scalar entity. - #[ subform_scalar( setter = false, hint = false ) ] + #[ subform_scalar( setter = false ) ] child : Child, } @@ -974,8 +974,8 @@ The `child` function within `ParentFormer` is a custom subform setter that plays // #[ debug ] pub struct Parent { - // Use `hint = true` to gennerate sketch of setter. - #[ scalar( setter = false, hint = false ) ] + // Use `debug` to gennerate sketch of setter. + #[ scalar( setter = false ) ] children : HashMap< String, Child >, } @@ -1055,8 +1055,8 @@ The `child` function within `ParentFormer` is a custom subform setter that plays // #[ debug ] pub struct Parent { - // Use `hint = true` to gennerate sketch of setter. - #[ subform_entry( setter = false, hint = false ) ] + // Use `debug` to gennerate sketch of setter. + #[ subform_entry( setter = false ) ] child : HashMap< String, Child >, } @@ -1195,7 +1195,7 @@ held within the storage. #[ derive( Debug, PartialEq, Former ) ] #[ storage_fields( a : i32, b : Option< String > ) ] - #[ mutator( custom = true ) ] + #[ mutator( custom ) ] pub struct Struct1 { c : String, diff --git a/module/core/former/examples/former_custom_mutator.rs b/module/core/former/examples/former_custom_mutator.rs index 5d83fe77c9..e70323e588 100644 --- a/module/core/former/examples/former_custom_mutator.rs +++ b/module/core/former/examples/former_custom_mutator.rs @@ -41,7 +41,7 @@ fn main() #[ derive( Debug, PartialEq, Former ) ] #[ storage_fields( a : i32, b : Option< String > ) ] - #[ mutator( custom = true ) ] + #[ mutator( custom ) ] pub struct Struct1 { c : String, diff --git a/module/core/former/examples/former_custom_scalar_setter.rs b/module/core/former/examples/former_custom_scalar_setter.rs index ce0588352e..753adcc618 100644 --- a/module/core/former/examples/former_custom_scalar_setter.rs +++ b/module/core/former/examples/former_custom_scalar_setter.rs @@ -47,8 +47,8 @@ fn main() // #[ debug ] pub struct Parent { - // Use `hint = true` to gennerate sketch of setter. - #[ scalar( setter = false, hint = false ) ] + // Use `debug` to gennerate sketch of setter. + #[ scalar( setter = false ) ] children : HashMap< String, Child >, } diff --git a/module/core/former/examples/former_custom_setter_overriden.rs b/module/core/former/examples/former_custom_setter_overriden.rs index 08acd738a0..7c57e5eaa1 100644 --- a/module/core/former/examples/former_custom_setter_overriden.rs +++ b/module/core/former/examples/former_custom_setter_overriden.rs @@ -18,8 +18,8 @@ fn main() #[ derive( Debug, Former ) ] pub struct StructWithCustomSetters { - // Use `hint = true` to gennerate sketch of setter. - #[ scalar( setter = false, hint = false ) ] + // Use `debug` to gennerate sketch of setter. + #[ scalar( setter = false ) ] word : String, } diff --git a/module/core/former/examples/former_custom_subform_collection.rs b/module/core/former/examples/former_custom_subform_collection.rs index 963431d27a..f0de7350a0 100644 --- a/module/core/former/examples/former_custom_subform_collection.rs +++ b/module/core/former/examples/former_custom_subform_collection.rs @@ -47,8 +47,8 @@ fn main() // #[ debug ] pub struct Parent { - // Use `hint = true` to gennerate sketch of setter. - #[ subform_collection( setter = false, hint = false ) ] + // Use `debug` to gennerate sketch of setter. + #[ subform_collection( setter = false ) ] children : HashMap< String, Child >, } diff --git a/module/core/former/examples/former_custom_subform_entry.rs b/module/core/former/examples/former_custom_subform_entry.rs index 865282012f..e046434da8 100644 --- a/module/core/former/examples/former_custom_subform_entry.rs +++ b/module/core/former/examples/former_custom_subform_entry.rs @@ -47,8 +47,8 @@ fn main() // #[ debug ] pub struct Parent { - // Use `hint = true` to gennerate sketch of setter. - #[ subform_entry( setter = false, hint = false ) ] + // Use `debug` to gennerate sketch of setter. + #[ subform_entry( setter = false ) ] child : HashMap< String, Child >, } diff --git a/module/core/former/examples/former_custom_subform_entry2.rs b/module/core/former/examples/former_custom_subform_entry2.rs index d3eebbab21..c4592ee34f 100644 --- a/module/core/former/examples/former_custom_subform_entry2.rs +++ b/module/core/former/examples/former_custom_subform_entry2.rs @@ -47,8 +47,8 @@ fn main() // #[ debug ] pub struct Parent { - // Use `hint = true` to gennerate sketch of setter. - #[ subform_entry( setter = false, hint = false ) ] + // Use `debug` to gennerate sketch of setter. + #[ subform_entry( setter = false ) ] child : HashMap< String, Child >, } diff --git a/module/core/former/examples/former_custom_subform_scalar.rs b/module/core/former/examples/former_custom_subform_scalar.rs index 395616579d..7bb0eb97cd 100644 --- a/module/core/former/examples/former_custom_subform_scalar.rs +++ b/module/core/former/examples/former_custom_subform_scalar.rs @@ -53,7 +53,7 @@ fn main() { // The `subform_scalar` attribute is used to specify that the 'child' field has its own former // and can be individually configured via a subform setter. This is not a collection but a single scalar entity. - #[ subform_scalar( setter = false, hint = false ) ] + #[ subform_scalar( setter = false ) ] child : Child, } diff --git a/module/core/former/tests/inc/components_tests/component_assign.rs b/module/core/former/tests/inc/components_tests/component_assign.rs index b2b1fdde8b..546cb3852b 100644 --- a/module/core/former/tests/inc/components_tests/component_assign.rs +++ b/module/core/former/tests/inc/components_tests/component_assign.rs @@ -1,10 +1,10 @@ #[ allow( unused_imports ) ] use super::*; #[ allow( unused_imports ) ] -use former::ComponentAssign; +use former::Assign; -#[ derive( Default, PartialEq, Debug, former::ComponentAssign ) ] +#[ derive( Default, PartialEq, Debug, former::Assign ) ] // #[ debug ] struct Person { diff --git a/module/core/former/tests/inc/components_tests/component_assign_manual.rs b/module/core/former/tests/inc/components_tests/component_assign_manual.rs index d858c5f989..fe1131845a 100644 --- a/module/core/former/tests/inc/components_tests/component_assign_manual.rs +++ b/module/core/former/tests/inc/components_tests/component_assign_manual.rs @@ -1,7 +1,7 @@ #[ allow( unused_imports ) ] use super::*; #[ allow( unused_imports ) ] -use former::ComponentAssign; +use former::Assign; #[ derive( Default, PartialEq, Debug ) ] @@ -11,7 +11,7 @@ struct Person name : String, } -impl< IntoT > ComponentAssign< i32, IntoT > for Person +impl< IntoT > Assign< i32, IntoT > for Person where IntoT : Into< i32 >, { @@ -21,7 +21,7 @@ where } } -impl< IntoT > ComponentAssign< String, IntoT > for Person +impl< IntoT > Assign< String, IntoT > for Person where IntoT : Into< String >, { diff --git a/module/core/former/tests/inc/components_tests/components_assign.rs b/module/core/former/tests/inc/components_tests/components_assign.rs index 84f01db2a8..2867a3cc8b 100644 --- a/module/core/former/tests/inc/components_tests/components_assign.rs +++ b/module/core/former/tests/inc/components_tests/components_assign.rs @@ -1,13 +1,13 @@ #[ allow( unused_imports ) ] use super::*; #[ allow( unused_imports ) ] -use former::{ ComponentAssign, AssignWithType }; +use former::{ Assign, AssignWithType }; /// /// Options1 /// -#[ derive( Debug, Default, PartialEq, the_module::ComponentAssign, the_module::ComponentsAssign ) ] +#[ derive( Debug, Default, PartialEq, the_module::Assign, the_module::ComponentsAssign ) ] pub struct Options1 { field1 : i32, @@ -46,7 +46,7 @@ impl From< &Options1 > for f32 /// Options2 /// -#[ derive( Debug, Default, PartialEq, the_module::ComponentAssign, the_module::ComponentsAssign ) ] +#[ derive( Debug, Default, PartialEq, the_module::Assign, the_module::ComponentsAssign ) ] pub struct Options2 { field1 : i32, diff --git a/module/core/former/tests/inc/components_tests/components_assign_manual.rs b/module/core/former/tests/inc/components_tests/components_assign_manual.rs index 9d7907d05f..bc88f29e14 100644 --- a/module/core/former/tests/inc/components_tests/components_assign_manual.rs +++ b/module/core/former/tests/inc/components_tests/components_assign_manual.rs @@ -1,7 +1,7 @@ #[ allow( unused_imports ) ] use super::*; #[ allow( unused_imports ) ] -use former::{ ComponentAssign, AssignWithType }; +use former::{ Assign, AssignWithType }; /// /// Options1 @@ -42,7 +42,7 @@ impl From< &Options1 > for f32 } } -impl< IntoT > former::ComponentAssign< i32, IntoT > for Options1 +impl< IntoT > former::Assign< i32, IntoT > for Options1 where IntoT : Into< i32 >, { @@ -53,7 +53,7 @@ where } } -impl< IntoT > former::ComponentAssign< String, IntoT > for Options1 +impl< IntoT > former::Assign< String, IntoT > for Options1 where IntoT : Into< String >, { @@ -64,7 +64,7 @@ where } } -impl< IntoT > former::ComponentAssign< f32, IntoT > for Options1 +impl< IntoT > former::Assign< f32, IntoT > for Options1 where IntoT : Into< f32 >, { @@ -93,9 +93,9 @@ where // #[ allow( dead_code ) ] impl< T, IntoT > Options1ComponentsAssign< IntoT > for T where - T : former::ComponentAssign< i32, IntoT >, - T : former::ComponentAssign< String, IntoT >, - T : former::ComponentAssign< f32, IntoT >, + T : former::Assign< i32, IntoT >, + T : former::Assign< String, IntoT >, + T : former::Assign< f32, IntoT >, IntoT : Into< i32 >, IntoT : Into< String >, IntoT : Into< f32 >, @@ -104,9 +104,9 @@ where #[ inline( always ) ] fn options_1_assign( &mut self, component : IntoT ) { - former::ComponentAssign::< i32, _ >::assign( self, component.clone() ); - former::ComponentAssign::< String, _ >::assign( self, component.clone() ); - former::ComponentAssign::< f32, _ >::assign( self, component.clone() ); + former::Assign::< i32, _ >::assign( self, component.clone() ); + former::Assign::< String, _ >::assign( self, component.clone() ); + former::Assign::< f32, _ >::assign( self, component.clone() ); } } @@ -139,7 +139,7 @@ impl From< &Options2 > for String } } -impl< IntoT > former::ComponentAssign< i32, IntoT > for Options2 +impl< IntoT > former::Assign< i32, IntoT > for Options2 where IntoT : Into< i32 >, { @@ -150,7 +150,7 @@ where } } -impl< IntoT > former::ComponentAssign< String, IntoT > for Options2 +impl< IntoT > former::Assign< String, IntoT > for Options2 where IntoT : Into< String >, { @@ -176,8 +176,8 @@ where impl< T, IntoT > Options2ComponentsAssign< IntoT > for T where - T : former::ComponentAssign< i32, IntoT >, - T : former::ComponentAssign< String, IntoT >, + T : former::Assign< i32, IntoT >, + T : former::Assign< String, IntoT >, IntoT : Into< i32 >, IntoT : Into< String >, IntoT : Clone, @@ -185,8 +185,8 @@ where #[ inline( always ) ] fn options_2_assign( &mut self, component : IntoT ) { - former::ComponentAssign::< i32, _ >::assign( self, component.clone() ); - former::ComponentAssign::< String, _ >::assign( self, component.clone() ); + former::Assign::< i32, _ >::assign( self, component.clone() ); + former::Assign::< String, _ >::assign( self, component.clone() ); } } diff --git a/module/core/former/tests/inc/components_tests/composite.rs b/module/core/former/tests/inc/components_tests/composite.rs index 723f3be16c..091fcc268b 100644 --- a/module/core/former/tests/inc/components_tests/composite.rs +++ b/module/core/former/tests/inc/components_tests/composite.rs @@ -1,7 +1,7 @@ #[ allow( unused_imports ) ] use super::*; #[ allow( unused_imports ) ] -use former::{ ComponentAssign, AssignWithType }; +use former::{ Assign, AssignWithType }; /// /// Options1 @@ -14,7 +14,7 @@ use former::{ ComponentAssign, AssignWithType }; Default, PartialEq, the_module::ComponentFrom, - the_module::ComponentAssign, + the_module::Assign, the_module::ComponentsAssign, the_module::FromComponents, ) @@ -38,7 +38,7 @@ pub struct Options1 Default, PartialEq, the_module::ComponentFrom, - the_module::ComponentAssign, + the_module::Assign, the_module::ComponentsAssign, the_module::FromComponents, ) diff --git a/module/core/former/tests/inc/components_tests/composite_manual.rs b/module/core/former/tests/inc/components_tests/composite_manual.rs index 03fc1f28f9..276def66ae 100644 --- a/module/core/former/tests/inc/components_tests/composite_manual.rs +++ b/module/core/former/tests/inc/components_tests/composite_manual.rs @@ -1,7 +1,7 @@ #[ allow( unused_imports ) ] use super::*; #[ allow( unused_imports ) ] -use former::{ ComponentAssign, AssignWithType }; +use former::{ Assign, AssignWithType }; /// /// Options1 @@ -42,7 +42,7 @@ impl From< &Options1 > for f32 } } -impl< IntoT > former::ComponentAssign< i32, IntoT > for Options1 +impl< IntoT > former::Assign< i32, IntoT > for Options1 where IntoT : Into< i32 >, { @@ -53,7 +53,7 @@ where } } -impl< IntoT > former::ComponentAssign< String, IntoT > for Options1 +impl< IntoT > former::Assign< String, IntoT > for Options1 where IntoT : Into< String >, { @@ -64,7 +64,7 @@ where } } -impl< IntoT > former::ComponentAssign< f32, IntoT > for Options1 +impl< IntoT > former::Assign< f32, IntoT > for Options1 where IntoT : Into< f32 >, { @@ -91,9 +91,9 @@ where impl< T, IntoT > Options1ComponentsAssign< IntoT > for T where - T : former::ComponentAssign< i32, IntoT >, - T : former::ComponentAssign< String, IntoT >, - T : former::ComponentAssign< f32, IntoT >, + T : former::Assign< i32, IntoT >, + T : former::Assign< String, IntoT >, + T : former::Assign< f32, IntoT >, IntoT : Into< i32 >, IntoT : Into< String >, IntoT : Into< f32 >, @@ -102,9 +102,9 @@ where #[ inline( always ) ] fn options_1_assign( &mut self, component : IntoT ) { - former::ComponentAssign::< i32, _ >::assign( self, component.clone() ); - former::ComponentAssign::< String, _ >::assign( self, component.clone() ); - former::ComponentAssign::< f32, _ >::assign( self, component.clone() ); + former::Assign::< i32, _ >::assign( self, component.clone() ); + former::Assign::< String, _ >::assign( self, component.clone() ); + former::Assign::< f32, _ >::assign( self, component.clone() ); } } @@ -137,7 +137,7 @@ impl From< &Options2 > for String } } -impl< IntoT > former::ComponentAssign< i32, IntoT > for Options2 +impl< IntoT > former::Assign< i32, IntoT > for Options2 where IntoT : Into< i32 >, { @@ -148,7 +148,7 @@ where } } -impl< IntoT > former::ComponentAssign< String, IntoT > for Options2 +impl< IntoT > former::Assign< String, IntoT > for Options2 where IntoT : Into< String >, { @@ -174,8 +174,8 @@ where impl< T, IntoT > Options2ComponentsAssign< IntoT > for T where - T : former::ComponentAssign< i32, IntoT >, - T : former::ComponentAssign< String, IntoT >, + T : former::Assign< i32, IntoT >, + T : former::Assign< String, IntoT >, IntoT : Into< i32 >, IntoT : Into< String >, IntoT : Clone, @@ -183,8 +183,8 @@ where #[ inline( always ) ] fn options_2_assign( &mut self, component : IntoT ) { - former::ComponentAssign::< i32, _ >::assign( self, component.clone() ); - former::ComponentAssign::< String, _ >::assign( self, component.clone() ); + former::Assign::< i32, _ >::assign( self, component.clone() ); + former::Assign::< String, _ >::assign( self, component.clone() ); } } diff --git a/module/core/former/tests/inc/former_tests/attribute_multiple.rs b/module/core/former/tests/inc/former_tests/attribute_multiple.rs new file mode 100644 index 0000000000..55c3745e8d --- /dev/null +++ b/module/core/former/tests/inc/former_tests/attribute_multiple.rs @@ -0,0 +1,34 @@ +#[ allow( unused_imports ) ] +use super::*; + +#[ derive( Debug, PartialEq, the_module::Former ) ] +pub struct Struct1 +{ + + #[ former( default = collection_tools::vec![ 1, 2, 3 ] ) ] + #[ former( default = collection_tools::vec![ 2, 3, 4 ] ) ] + vec_ints : Vec< i32 >, + +} + +// + +tests_impls! +{ + fn test_complex() + { + let command = Struct1::former().form(); + let expected = Struct1 + { + vec_ints : collection_tools::vec![ 2, 3, 4 ], + }; + a_id!( command, expected ); + } +} + +// + +tests_index! +{ + test_complex, +} diff --git a/module/core/former/tests/inc/former_tests/attribute_storage_with_mutator.rs b/module/core/former/tests/inc/former_tests/attribute_storage_with_mutator.rs index 57936294d3..983fbc655e 100644 --- a/module/core/former/tests/inc/former_tests/attribute_storage_with_mutator.rs +++ b/module/core/former/tests/inc/former_tests/attribute_storage_with_mutator.rs @@ -3,7 +3,7 @@ use super::*; #[ derive( Debug, PartialEq, the_module::Former ) ] #[ storage_fields( a : i32, b : Option< String > ) ] -#[ mutator( custom = true ) ] +#[ mutator( custom ) ] // #[ debug ] // #[ derive( Debug, PartialEq ) ] pub struct Struct1 diff --git a/module/core/former/tests/inc/former_tests/tuple_struct.rs b/module/core/former/tests/inc/former_tests/tuple_struct.rs index 57f13ec1d6..2925f0f592 100644 --- a/module/core/former/tests/inc/former_tests/tuple_struct.rs +++ b/module/core/former/tests/inc/former_tests/tuple_struct.rs @@ -3,33 +3,35 @@ #[ allow( unused_imports ) ] use super::*; -use collection_tools::HashMap; +// xxx : qqq : make that working -type Key = &'static str; -type Value = &'static str; - -#[ derive( Debug, PartialEq, former::Former ) ] -pub struct Struct1( #[ subform_collection ] HashMap< Key, Value > ); - -impl Struct1 -{ - pub fn get( &self, key : Key ) -> Option< &Value > - { - self.0.get( key ) - } -} - -#[ test ] -fn example() -{ - // form a key-value store - let instance = Struct1::former() - .map() - .add( ( "first", "Value1" ) ) - .add( ( "second", "Value2" ) ) - .end() - .form(); - - // now it is a read-only storage with pre-configured data - assert_eq!( Some( &"Value1" ), instance.get( "first" ) ); -} +// use collection_tools::HashMap; +// +// type Key = &'static str; +// type Value = &'static str; +// +// #[ derive( Debug, PartialEq, former::Former ) ] +// pub struct Struct1( #[ subform_collection ] HashMap< Key, Value > ); +// +// impl Struct1 +// { +// pub fn get( &self, key : Key ) -> Option< &Value > +// { +// self.0.get( key ) +// } +// } +// +// #[ test ] +// fn example() +// { +// // form a key-value store +// let instance = Struct1::former() +// .map() +// .add( ( "first", "Value1" ) ) +// .add( ( "second", "Value2" ) ) +// .end() +// .form(); +// +// // now it is a read-only storage with pre-configured data +// assert_eq!( Some( &"Value1" ), instance.get( "first" ) ); +// } diff --git a/module/core/former/tests/inc/mod.rs b/module/core/former/tests/inc/mod.rs index a4351febf9..30bcd81c0f 100644 --- a/module/core/former/tests/inc/mod.rs +++ b/module/core/former/tests/inc/mod.rs @@ -39,6 +39,7 @@ mod former_tests mod attribute_setter; mod attribute_alias; mod attribute_feature; + mod attribute_multiple; // = name collision diff --git a/module/core/former_meta/Cargo.toml b/module/core/former_meta/Cargo.toml index 770817a07f..04ea67bfca 100644 --- a/module/core/former_meta/Cargo.toml +++ b/module/core/former_meta/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "former_meta" -version = "2.0.0" +version = "2.1.0" edition = "2021" authors = [ "Kostiantyn Wandalen ", @@ -58,7 +58,7 @@ proc-macro = true [dependencies] macro_tools = { workspace = true } # qqq : optimize set of features -former_types = { workspace = true, features = [ "types_component_assign" ] } # qqq : optimize set of features +former_types = { workspace = true, features = [ "enabled", "types_component_assign" ] } iter_tools = { workspace = true } convert_case = { version = "0.6.0", default-features = false, optional = true, features = [] } const_format = { version = "0.2.32" } diff --git a/module/core/former_meta/src/component/component_assign.rs b/module/core/former_meta/src/component/component_assign.rs index a08bf9b696..de12fc7f5f 100644 --- a/module/core/former_meta/src/component/component_assign.rs +++ b/module/core/former_meta/src/component/component_assign.rs @@ -2,7 +2,7 @@ use super::*; use macro_tools::{ attr, diag, Result }; /// -/// Generates implementations of the `ComponentAssign` trait for each field of a struct. +/// Generates implementations of the `Assign` trait for each field of a struct. /// pub fn component_assign( input : proc_macro::TokenStream ) -> Result< proc_macro2::TokenStream > { @@ -24,18 +24,18 @@ pub fn component_assign( input : proc_macro::TokenStream ) -> Result< proc_macro if has_debug { - let about = format!( "derive : ComponentAssign\nstructure : {item_name}" ); + let about = format!( "derive : Assign\nstructure : {item_name}" ); diag::report_print( about, &original_input, &result ); } Ok( result ) } -/// Generates an implementation of the `ComponentAssign` trait for a specific field of a struct. +/// Generates an implementation of the `Assign` trait for a specific field of a struct. /// /// This function creates the trait implementation that enables setting a struct's field value /// with a type that can be converted into the field's type. It dynamically generates code -/// during the macro execution to provide `ComponentAssign` trait implementations for each field +/// during the macro execution to provide `Assign` trait implementations for each field /// of the struct, facilitating an ergonomic API for modifying struct instances. /// /// # Parameters @@ -46,7 +46,7 @@ pub fn component_assign( input : proc_macro::TokenStream ) -> Result< proc_macro /// # Example of generated code /// /// ```rust, ignore -/// impl< IntoT > former::ComponentAssign< i32, IntoT > for Options1 +/// impl< IntoT > former::Assign< i32, IntoT > for Options1 /// where /// IntoT : Into< i32 >, /// { @@ -66,7 +66,7 @@ fn for_each_field( field : &syn::Field, item_name : &syn::Ident ) -> Result< pro Ok( qt! { #[ allow( non_snake_case ) ] - impl< IntoT > ComponentAssign< #field_type, IntoT > for #item_name + impl< IntoT > Assign< #field_type, IntoT > for #item_name where IntoT : Into< #field_type >, { diff --git a/module/core/former_meta/src/component/components_assign.rs b/module/core/former_meta/src/component/components_assign.rs index 4a69425dd3..6b495e7629 100644 --- a/module/core/former_meta/src/component/components_assign.rs +++ b/module/core/former_meta/src/component/components_assign.rs @@ -1,6 +1,6 @@ use super::*; -use macro_tools::{ attr, diag, Result }; -use iter_tools::{ Itertools, process_results }; +use macro_tools::{ attr, diag, Result, format_ident }; +use iter_tools::{ Itertools }; /// /// Generate `ComponentsAssign` trait implementation for the type, providing `components_assign` function @@ -17,13 +17,19 @@ pub fn components_assign( input : proc_macro::TokenStream ) -> Result< proc_macr // name let item_name = &parsed.ident; - let trait_name = format!( "{}ComponentsAssign", item_name ); - let trait_ident = syn::Ident::new( &trait_name, item_name.span() ); - let method_name = format!( "{}_assign", item_name.to_string().to_case( Case::Snake ) ); - let method_ident = syn::Ident::new( &method_name, item_name.span() ); - // xxx : use macro ident_format!() + let trait_ident = format_ident! + { + "{}ComponentsAssign", + item_name + }; + let method_ident = format_ident! + { + "{}_assign", + item_name.to_string().to_case( Case::Snake ) + }; // fields +// fields let ( bounds1, bounds2, component_assigns ) : ( Vec< _ >, Vec< _ >, Vec< _ > ) = parsed.fields.iter().map( | field | { let field_type = &field.ty; @@ -33,9 +39,9 @@ pub fn components_assign( input : proc_macro::TokenStream ) -> Result< proc_macr ( bound1, bound2, component_assign ) }).multiunzip(); - let bounds1 : Vec< _ > = process_results( bounds1, | iter | iter.collect() )?; - let bounds2 : Vec< _ > = process_results( bounds2, | iter | iter.collect() )?; - let component_assigns : Vec< _ > = process_results( component_assigns, | iter | iter.collect() )?; + let bounds1 : Vec< _ > = bounds1.into_iter().collect::< Result< _ > >()?; + let bounds2 : Vec< _ > = bounds2.into_iter().collect::< Result< _ > >()?; + let component_assigns : Vec< _ > = component_assigns.into_iter().collect::< Result< _ > >()?; // code let doc = format!( "Interface to assign instance from set of components exposed by a single argument." ); @@ -107,7 +113,7 @@ fn generate_trait_bounds( field_type : &syn::Type ) -> Result< proc_macro2::Toke /// ### Output example /// /// ```ignore -/// T : former::ComponentAssign< i32, IntoT >, +/// T : former::Assign< i32, IntoT >, /// ``` /// fn generate_impl_bounds( field_type : &syn::Type ) -> Result< proc_macro2::TokenStream > @@ -116,7 +122,7 @@ fn generate_impl_bounds( field_type : &syn::Type ) -> Result< proc_macro2::Token ( qt! { - T : former::ComponentAssign< #field_type, IntoT >, + T : former::Assign< #field_type, IntoT >, } ) } @@ -128,7 +134,7 @@ fn generate_impl_bounds( field_type : &syn::Type ) -> Result< proc_macro2::Token /// Output example /// /// ```ignore -/// former::ComponentAssign::< i32, _ >::assign( self.component.clone() ); +/// former::Assign::< i32, _ >::assign( self.component.clone() ); /// ``` /// fn generate_component_assign_call( field : &syn::Field ) -> Result< proc_macro2::TokenStream > @@ -139,7 +145,7 @@ fn generate_component_assign_call( field : &syn::Field ) -> Result< proc_macro2: ( qt! { - former::ComponentAssign::< #field_type, _ >::assign( self, component.clone() ); + former::Assign::< #field_type, _ >::assign( self, component.clone() ); } ) } diff --git a/module/core/former_meta/src/derive_former.rs b/module/core/former_meta/src/derive_former.rs index d3093505cd..d79534fb02 100644 --- a/module/core/former_meta/src/derive_former.rs +++ b/module/core/former_meta/src/derive_former.rs @@ -1,6 +1,6 @@ use super::*; -use iter_tools::{ Itertools, process_results }; +use iter_tools::{ Itertools }; use macro_tools::{ attr, diag, generic_params, generic_args, typ, derive, Result }; use proc_macro2::TokenStream; @@ -43,7 +43,7 @@ use struct_attrs::*; pub fn mutator ( - stru : &syn::Ident, + item : &syn::Ident, original_input : &proc_macro::TokenStream, mutator : &AttributeMutator, former_definition_types : &syn::Ident, @@ -53,7 +53,7 @@ pub fn mutator ) -> Result< TokenStream > { - let former_mutator_code = if mutator.custom.into() + let former_mutator_code = if mutator.custom.value( false ) { qt!{} } @@ -70,9 +70,9 @@ pub fn mutator } }; - if mutator.hint.into() + if mutator.debug.value( false ) { - let hint = format! + let debug = format! ( r#" = Example of custom mutator @@ -93,13 +93,13 @@ where format!( "{}", qt!{ #former_definition_types_generics_ty } ), format!( "{}", qt!{ #former_definition_types_generics_where } ), ); - // println!( "{hint}" ); + // println!( "{debug}" ); let about = format! ( r#"derive : Former -structure : {stru}"#, +item : {item}"#, ); - diag::report_print( about, original_input, hint ); + diag::report_print( about, original_input, debug ); }; Ok( former_mutator_code ) @@ -109,14 +109,14 @@ structure : {stru}"#, /// Generate documentation for the former. /// -fn doc_generate( stru : &syn::Ident ) -> ( String, String ) +fn doc_generate( item : &syn::Ident ) -> ( String, String ) { let doc_former_mod = format! ( r#" Implementation of former for [{}]. "#, - stru + item ); let doc_former_struct = format! @@ -127,7 +127,7 @@ Structure to form [{}]. Represents a forming entity designed to construct object This structure holds temporary storage and context during the formation process and utilizes a defined end strategy to finalize the object creation. "#, - stru + item ); ( doc_former_mod, doc_former_struct ) @@ -150,29 +150,23 @@ pub fn former( input : proc_macro::TokenStream ) -> Result< TokenStream > Err( err ) => return Err( err ), }; let has_debug = attr::has_debug( ast.attrs.iter() )?; - let struct_attrs = StructAttributes::from_attrs( ast.attrs.iter() )?; + let struct_attrs = ItemAttributes::from_attrs( ast.attrs.iter() )?; /* names */ let vis = &ast.vis; - let stru = &ast.ident; - let former_name = format!( "{}Former", stru ); - let former = syn::Ident::new( &former_name, stru.span() ); - let former_storage_name = format!( "{}FormerStorage", stru ); - let former_storage = syn::Ident::new( &former_storage_name, stru.span() ); - let former_definition_name = format!( "{}FormerDefinition", stru ); - let former_definition = syn::Ident::new( &former_definition_name, stru.span() ); - let former_definition_types_name = format!( "{}FormerDefinitionTypes", stru ); - let former_definition_types = syn::Ident::new( &former_definition_types_name, stru.span() ); - let as_subformer_name = format!( "{}AsSubformer", stru ); - let as_subformer = syn::Ident::new( &as_subformer_name, stru.span() ); - let as_subformer_end_name = format!( "{}AsSubformerEnd", stru ); - let as_subformer_end = syn::Ident::new( &as_subformer_end_name, stru.span() ); + let item = &ast.ident; + let former = format_ident!( "{item}Former" ); + let former_storage = format_ident!( "{item}FormerStorage" ); + let former_definition = format_ident!( "{item}FormerDefinition" ); + let former_definition_types = format_ident!( "{item}FormerDefinitionTypes" ); + let as_subformer = format_ident!( "{item}AsSubformer" ); + let as_subformer_end = format_ident!( "{item}AsSubformerEnd" ); let as_subformer_end_doc = format! ( r#" -Represents an end condition for former of [`${stru}`], tying the lifecycle of forming processes to a broader context. +Represents an end condition for former of [`${item}`], tying the lifecycle of forming processes to a broader context. This trait is intended for use with subformer alias, ensuring that end conditions are met according to the specific needs of the broader forming context. It mandates the implementation of `former::FormingEnd`. @@ -189,7 +183,7 @@ specific needs of the broader forming context. It mandates the implementation of let extra : macro_tools::syn::AngleBracketedGenericArguments = parse_quote! { - < (), #stru < #struct_generics_ty >, former::ReturnPreformed > + < (), #item < #struct_generics_ty >, former::ReturnPreformed > }; let former_definition_args = generic_args::merge( &generics.into_generic_args(), &extra.into() ).args; @@ -216,12 +210,12 @@ specific needs of the broader forming context. It mandates the implementation of Definition : former::FormerDefinition < Storage = #former_storage < #struct_generics_ty >, - Formed = #stru < #struct_generics_ty >, + Formed = #item < #struct_generics_ty >, >, Definition::Types : former::FormerDefinitionTypes < Storage = #former_storage < #struct_generics_ty >, - Formed = #stru < #struct_generics_ty >, + Formed = #item < #struct_generics_ty >, >, }; let extra = generic_params::merge( &generics, &extra.into() ); @@ -233,7 +227,7 @@ specific needs of the broader forming context. It mandates the implementation of let extra : macro_tools::GenericsWithWhere = parse_quote! { - < __Context = (), __Formed = #stru < #struct_generics_ty > > + < __Context = (), __Formed = #item < #struct_generics_ty > > }; let former_definition_types_generics = generic_params::merge( &generics, &extra.into() ); let ( former_definition_types_generics_with_defaults, former_definition_types_generics_impl, former_definition_types_generics_ty, former_definition_types_generics_where ) @@ -245,7 +239,7 @@ specific needs of the broader forming context. It mandates the implementation of let extra : macro_tools::GenericsWithWhere = parse_quote! { - < __Context = (), __Formed = #stru < #struct_generics_ty >, __End = former::ReturnPreformed > + < __Context = (), __Formed = #item < #struct_generics_ty >, __End = former::ReturnPreformed > }; let generics_of_definition = generic_params::merge( &generics, &extra.into() ); let ( former_definition_generics_with_defaults, former_definition_generics_impl, former_definition_generics_ty, former_definition_generics_where ) @@ -255,31 +249,29 @@ specific needs of the broader forming context. It mandates the implementation of /* struct attributes */ - let ( _doc_former_mod, doc_former_struct ) = doc_generate( stru ); + let ( _doc_former_mod, doc_former_struct ) = doc_generate( item ); let ( perform, perform_output, perform_generics ) = struct_attrs.performer()?; /* fields */ let fields = derive::named_fields( &ast )?; - let formed_fields : Vec< Result< FormerField< '_ > > > = fields + let formed_fields : Vec< _ > = fields .into_iter() .map( | field | { FormerField::from_syn( field, true, true ) }) - .collect(); - let formed_fields : Vec< _ > = process_results( formed_fields, | iter | iter.collect() )?; + .collect::< Result< _ > >()?; - let storage_fields : Vec< Result< FormerField< '_ > > > = struct_attrs + let storage_fields : Vec< _ > = struct_attrs .storage_fields() .iter() .map( | field | { - FormerField::from_syn( &field, true, false ) + FormerField::from_syn( field, true, false ) }) - .collect(); - let storage_fields : Vec< _ > = process_results( storage_fields, | iter | iter.collect() )?; + .collect::< Result< _ > >()?; let ( @@ -302,7 +294,7 @@ specific needs of the broader forming context. It mandates the implementation of field.storage_field_preform(), field.former_field_setter ( - &stru, + &item, &original_input, &struct_generics_impl, &struct_generics_ty, @@ -318,11 +310,14 @@ specific needs of the broader forming context. It mandates the implementation of let results : Result< Vec< _ > > = former_field_setter.into_iter().collect(); let ( former_field_setter, namespace_code ) : ( Vec< _ >, Vec< _ > ) = results?.into_iter().unzip(); - let storage_field_preform : Vec< _ > = process_results( storage_field_preform, | iter | iter.collect() )?; + // let storage_field_preform : Vec< _ > = process_results( storage_field_preform, | iter | iter.collect() )?; + let storage_field_preform : Vec< _ > = storage_field_preform + .into_iter() + .collect::< Result< _ > >()?; let former_mutator_code = mutator ( - &stru, + &item, &original_input, &struct_attrs.mutator, &former_definition_types, @@ -337,7 +332,7 @@ specific needs of the broader forming context. It mandates the implementation of // = formed #[ automatically_derived ] - impl < #struct_generics_impl > #stru < #struct_generics_ty > + impl < #struct_generics_impl > #item < #struct_generics_ty > where #struct_generics_where { @@ -357,7 +352,7 @@ specific needs of the broader forming context. It mandates the implementation of // = entity to former impl< #struct_generics_impl Definition > former::EntityToFormer< Definition > - for #stru < #struct_generics_ty > + for #item < #struct_generics_ty > where Definition : former::FormerDefinition< Storage = #former_storage < #struct_generics_ty > >, #struct_generics_where @@ -366,7 +361,7 @@ specific needs of the broader forming context. It mandates the implementation of } impl< #struct_generics_impl > former::EntityToStorage - for #stru < #struct_generics_ty > + for #item < #struct_generics_ty > where #struct_generics_where { @@ -374,7 +369,7 @@ specific needs of the broader forming context. It mandates the implementation of } impl< #struct_generics_impl __Context, __Formed, __End > former::EntityToDefinition< __Context, __Formed, __End > - for #stru < #struct_generics_ty > + for #item < #struct_generics_ty > where __End : former::FormingEnd< #former_definition_types < #struct_generics_ty __Context, __Formed > >, #struct_generics_where @@ -384,7 +379,7 @@ specific needs of the broader forming context. It mandates the implementation of } impl< #struct_generics_impl __Context, __Formed > former::EntityToDefinitionTypes< __Context, __Formed > - for #stru < #struct_generics_ty > + for #item < #struct_generics_ty > where #struct_generics_where { @@ -506,7 +501,7 @@ specific needs of the broader forming context. It mandates the implementation of where #struct_generics_where { - type Preformed = #stru < #struct_generics_ty >; + type Preformed = #item < #struct_generics_ty >; } impl < #struct_generics_impl > former::StoragePreform @@ -514,14 +509,14 @@ specific needs of the broader forming context. It mandates the implementation of where #struct_generics_where { - // type Preformed = #stru < #struct_generics_ty >; + // type Preformed = #item < #struct_generics_ty >; fn preform( mut self ) -> Self::Preformed { #( #storage_field_preform )* // Rust does not support that, yet // let result = < Definition::Types as former::FormerDefinitionTypes >::Formed - let result = #stru :: < #struct_generics_ty > + let result = #item :: < #struct_generics_ty > { #( #storage_field_name )* // #( #storage_field_name, )* @@ -660,8 +655,8 @@ specific needs of the broader forming context. It mandates the implementation of impl< #former_generics_impl > #former< #former_generics_ty > where - Definition : former::FormerDefinition< Storage = #former_storage < #struct_generics_ty >, Formed = #stru < #struct_generics_ty > >, - Definition::Types : former::FormerDefinitionTypes< Storage = #former_storage < #struct_generics_ty >, Formed = #stru < #struct_generics_ty > >, + Definition : former::FormerDefinition< Storage = #former_storage < #struct_generics_ty >, Formed = #item < #struct_generics_ty > >, + Definition::Types : former::FormerDefinitionTypes< Storage = #former_storage < #struct_generics_ty >, Formed = #item < #struct_generics_ty > >, #former_generics_where { @@ -778,7 +773,7 @@ specific needs of the broader forming context. It mandates the implementation of if has_debug { - let about = format!( "derive : Former\nstructure : {stru}" ); + let about = format!( "derive : Former\nstructure : {item}" ); diag::report_print( about, &original_input, &result ); } diff --git a/module/core/former_meta/src/derive_former/field.rs b/module/core/former_meta/src/derive_former/field.rs index 015eba4a1c..13a702b308 100644 --- a/module/core/former_meta/src/derive_former/field.rs +++ b/module/core/former_meta/src/derive_former/field.rs @@ -330,7 +330,7 @@ scalar_setter_required pub fn former_field_setter ( &self, - stru : &syn::Ident, + item : &syn::Ident, original_input : &proc_macro::TokenStream, struct_generics_impl : &syn::punctuated::Punctuated< syn::GenericParam, syn::token::Comma >, struct_generics_ty : &syn::punctuated::Punctuated< syn::GenericParam, syn::token::Comma >, @@ -348,7 +348,7 @@ scalar_setter_required let namespace_code = qt! {}; let setters_code = self.scalar_setter ( - stru, + item, former, former_storage, original_input, @@ -359,7 +359,7 @@ scalar_setter_required { let ( setters_code2, namespace_code2 ) = self.subform_scalar_setter ( - stru, + item, former, former_storage, former_generics_ty, @@ -380,7 +380,7 @@ scalar_setter_required { let ( setters_code2, namespace_code2 ) = self.subform_collection_setter ( - stru, + item, former, former_storage, former_generics_impl, @@ -400,7 +400,7 @@ scalar_setter_required { let ( setters_code2, namespace_code2 ) = self.subform_entry_setter ( - stru, + item, former, former_storage, former_generics_ty, @@ -444,7 +444,7 @@ scalar_setter_required pub fn scalar_setter ( &self, - stru : &syn::Ident, + item : &syn::Ident, former : &syn::Ident, former_storage : &syn::Ident, original_input : &proc_macro::TokenStream, @@ -456,9 +456,9 @@ scalar_setter_required let setter_name = self.scalar_setter_name(); let attr = self.attrs.scalar.as_ref(); - if attr.is_some() && attr.unwrap().hint.into() + if attr.is_some() && attr.unwrap().debug.value( false ) { - let hint = format! + let debug = format! ( r#" impl< Definition > {former}< Definition > @@ -481,10 +481,10 @@ where let about = format! ( r#"derive : Former -structure : {stru} +item : {item} field : {field_ident}"#, ); - diag::report_print( about, original_input, hint ); + diag::report_print( about, original_input, debug ); } if !self.scalar_setter_required() @@ -524,7 +524,7 @@ field : {field_ident}"#, pub fn subform_collection_setter ( &self, - stru : &syn::Ident, + item : &syn::Ident, former : &syn::Ident, former_storage : &syn::Ident, former_generics_impl : &syn::punctuated::Punctuated< syn::GenericParam, syn::token::Comma >, @@ -540,11 +540,21 @@ field : {field_ident}"#, let params = typ::type_parameters( &field_typ, .. ); use convert_case::{ Case, Casing }; - let subform_collection_end_name = format!( "{}SubformCollection{}End", stru, field_ident.to_string().to_case( Case::Pascal ) ); - let subform_collection_end = syn::Ident::new( &subform_collection_end_name, field_ident.span() ); - let subform_collection_name = format!( "_{}_subform_collection", field_ident ); - let subform_collection = syn::Ident::new( &subform_collection_name, field_ident.span() ); + // example : `ParentSubformCollectionChildrenEnd` + let subform_collection_end = format_ident! + { + "{}SubformCollection{}End", + item, + field_ident.to_string().to_case( Case::Pascal ) + }; + + // example : `_children_subform_collection` + let subform_collection = format_ident! + { + "_{}_subform_collection", + field_ident + }; // example : `former::VectorDefinition` let subformer_definition = &attr.definition; let subformer_definition = if subformer_definition.is_some() @@ -576,7 +586,7 @@ field : {field_ident}"#, ( "Collection setter for the '{}' field. Method {} unlike method {} accept custom collection subformer.", field_ident, - subform_collection_name, + subform_collection, field_ident, ); @@ -682,9 +692,9 @@ field : {field_ident}"#, qt!{} }; - if attr.hint.into() + if attr.debug.value( false ) { - let hint = format! + let debug = format! ( r#" /// The collection setter provides a collection setter that returns a CollectionFormer tailored for managing a collection of child entities. It employs a generic collection definition to facilitate operations on the entire collection, such as adding or updating elements. @@ -712,10 +722,10 @@ where let about = format! ( r#"derive : Former -structure : {stru} +item : {item} field : {field_ident}"#, ); - diag::report_print( about, original_input, hint ); + diag::report_print( about, original_input, debug ); } let setters_code = qt! @@ -730,10 +740,10 @@ field : {field_ident}"#, let subform_collection_end_doc = format! ( r#" -A callback structure to manage the final stage of forming a `{0}` for the `{stru}` collection. +A callback structure to manage the final stage of forming a `{0}` for the `{item}` collection. -This callback is used to integrate the contents of a temporary `{0}` back into the original `{stru}` former -after the subforming process is completed. It replaces the existing content of the `{field_ident}` field in `{stru}` +This callback is used to integrate the contents of a temporary `{0}` back into the original `{item}` former +after the subforming process is completed. It replaces the existing content of the `{field_ident}` field in `{item}` with the new content generated during the subforming process. "#, format!( "{}", qt!{ #field_typ } ), @@ -844,7 +854,7 @@ with the new content generated during the subforming process. pub fn subform_entry_setter ( &self, - stru : &syn::Ident, + item : &syn::Ident, former : &syn::Ident, former_storage : &syn::Ident, former_generics_ty : &syn::punctuated::Punctuated< syn::GenericParam, syn::token::Comma >, @@ -867,29 +877,36 @@ with the new content generated during the subforming process. // example : `children` let setter_name = self.subform_entry_setter_name(); - // example : `ParentSubformEntryChildrenEnd`` - let subform_entry_end_name = format!( "{}SubformEntry{}End", stru, field_ident.to_string().to_case( Case::Pascal ) ); - let subform_entry_end = syn::Ident::new( &subform_entry_end_name, field_ident.span() ); + // example : `ParentSubformEntryChildrenEnd` + let subform_entry_end = format_ident! + { + "{}SubformEntry{}End", + item, + field_ident.to_string().to_case( Case::Pascal ) + }; // example : `_children_subform_entry` - let subform_entry_name = format!( "_{}_subform_entry", field_ident ); - let subform_entry = syn::Ident::new( &subform_entry_name, field_ident.span() ); + let subform_entry = format_ident! + { + "_{}_subform_entry", + field_ident + }; let doc = format! ( r#" -Initiates the addition of {field_ident} to the `{stru}` entity using a dedicated subformer. +Initiates the addition of {field_ident} to the `{item}` entity using a dedicated subformer. This method configures and returns a subformer specialized for the `{0}` entities' formation process, -which is part of the `{stru}` entity's construction. The subformer is set up with a specific end condition +which is part of the `{item}` entity's construction. The subformer is set up with a specific end condition handled by `{subform_entry_end}`, ensuring that the {field_ident} are properly integrated into the parent's structure once formed. # Returns Returns an instance of `Former2`, a subformer ready to begin the formation process for `{0}` entities, -allowing for dynamic and flexible construction of the `{stru}` entity's {field_ident}. +allowing for dynamic and flexible construction of the `{item}` entity's {field_ident}. "#, format!( "{}", qt!{ #field_typ } ), @@ -928,12 +945,12 @@ allowing for dynamic and flexible construction of the `{stru}` entity's {field_i let doc = format! ( r#" -Provides a user-friendly interface to add an instancce of {field_ident} to the {stru}. +Provides a user-friendly interface to add an instancce of {field_ident} to the {item}. # Returns Returns an instance of `Former2`, a subformer ready to begin the formation process for `{0}` entities, -allowing for dynamic and flexible construction of the `{stru}` entity's {field_ident}. +allowing for dynamic and flexible construction of the `{item}` entity's {field_ident}. "#, format!( "{}", qt!{ #field_typ } ), @@ -975,9 +992,9 @@ allowing for dynamic and flexible construction of the `{stru}` entity's {field_i setters_code }; - if attr.hint.into() + if attr.debug.value( false ) { - let hint = format! + let debug = format! ( r#" /// Initializes and configures a subformer for adding named child entities. This method leverages an internal function @@ -992,7 +1009,7 @@ where #[ inline( always ) ] pub fn {field_ident}( self ) -> {0}AsSubformer< Self, impl {0}AsSubformerEnd< Self > > {{ - self.{subform_entry_name}::< {0}Former< _ >, _, >() + self.{subform_entry}::< {0}Former< _ >, _, >() }} // Replace {0} with name of type of entry value. @@ -1003,10 +1020,10 @@ where let about = format! ( r#"derive : Former -structure : {stru} +item : {item} field : {field_ident}"#, ); - diag::report_print( about, original_input, hint ); + diag::report_print( about, original_input, debug ); } let doc = format! @@ -1014,11 +1031,11 @@ field : {field_ident}"#, r#" Implements the `FormingEnd` trait for `{subform_entry_end}` to handle the final -stage of the forming process for a `{stru}` collection that contains `{0}` elements. +stage of the forming process for a `{item}` collection that contains `{0}` elements. This implementation is tailored to manage the transition of {field_ident} elements from a substorage -temporary state into their final state within the `{stru}`'s storage. The function ensures -that the `{stru}`'s {field_ident} storage is initialized if not already set, and then adds the +temporary state into their final state within the `{item}`'s storage. The function ensures +that the `{item}`'s {field_ident} storage is initialized if not already set, and then adds the preformed elements to this storage. # Type Parameters @@ -1037,7 +1054,7 @@ preformed elements to this storage. # Returns Returns the updated `{former}` instance with newly added {field_ident}, completing the -formation process of the `{stru}`. +formation process of the `{item}`. "#, format!( "{}", qt!{ #field_typ } ), @@ -1071,7 +1088,7 @@ formation process of the `{stru}`. where Definition : former::FormerDefinition < - Storage = < #stru < #struct_generics_ty > as former::EntityToStorage >::Storage, + Storage = < #item < #struct_generics_ty > as former::EntityToStorage >::Storage, >, Types2 : former::FormerDefinitionTypes < @@ -1122,7 +1139,7 @@ formation process of the `{stru}`. pub fn subform_scalar_setter ( &self, - stru : &syn::Ident, + item : &syn::Ident, former : &syn::Ident, _former_storage : &syn::Ident, former_generics_ty : &syn::punctuated::Punctuated< syn::GenericParam, syn::token::Comma >, @@ -1143,22 +1160,29 @@ formation process of the `{stru}`. // example : `children` let setter_name = self.subform_scalar_setter_name(); - // example : `ParentSubformScalarChildrenEnd`` - let subform_scalar_end_name = format!( "{}SubformScalar{}End", stru, field_ident.to_string().to_case( Case::Pascal ) ); - let subform_scalar_end = syn::Ident::new( &subform_scalar_end_name, field_ident.span() ); + // example : `ParentSubformScalarChildrenEnd` + let subform_scalar_end = format_ident! + { + "{}SubformScalar{}End", + item, + field_ident.to_string().to_case( Case::Pascal ) + }; // example : `_children_subform_scalar` - let subform_scalar_name = format!( "_{}_subform_scalar", field_ident ); - let subform_scalar = syn::Ident::new( &subform_scalar_name, field_ident.span() ); + let subform_scalar = format_ident! + { + "_{}_subform_scalar", + field_ident + }; let doc = format! ( r#" -Initiates the scalar subformer for a `{0}` entity within a `{stru}`. +Initiates the scalar subformer for a `{0}` entity within a `{item}`. This function creates a subformer specifically for handling scalar values associated with a `{0}` entity, -leveraging a dedicated end structure to integrate the formed value seamlessly back into the `{stru}`. +leveraging a dedicated end structure to integrate the formed value seamlessly back into the `{item}`. ## Type Parameters @@ -1169,7 +1193,7 @@ leveraging a dedicated end structure to integrate the formed value seamlessly ba - `Former2`: An instance of the former configured to handle the scalar formation of a `{0}`. -This method prepares the forming context, ensuring that the subforming process for a scalar field in `{stru}` +This method prepares the forming context, ensuring that the subforming process for a scalar field in `{item}` is properly initialized with all necessary configurations, including the default end action for integration. ## Usage @@ -1237,14 +1261,14 @@ generics, providing a cleaner interface for initiating subform operations on sca let doc = format! ( r#" -Provides a user-friendly interface to begin subforming a scalar `{0}` field within a `{stru}`. +Provides a user-friendly interface to begin subforming a scalar `{0}` field within a `{item}`. This method abstracts the underlying complex generics involved in setting up the former, simplifying the user interaction needed to initiate the subform process for a scalar field associated with a `{0}`. This method utilizes the more generic `{subform_scalar}` method to set up and return the subformer, providing a straightforward and type-safe interface for client code. It encapsulates details about the specific -former and end action types, ensuring a seamless developer experience when forming parts of a `{stru}`. +former and end action types, ensuring a seamless developer experience when forming parts of a `{item}`. "#, format!( "{}", qt!{ #field_typ } ), @@ -1285,9 +1309,9 @@ former and end action types, ensuring a seamless developer experience when formi setters_code }; - if attr.hint.into() + if attr.debug.value( false ) { - let hint = format! + let debug = format! ( r#" /// Extends `{former}` to include a method that initializes and configures a subformer for the '{field_ident}' field. @@ -1295,7 +1319,7 @@ former and end action types, ensuring a seamless developer experience when formi impl< Definition > {former}< Definition > where - Definition : former::FormerDefinition< Storage = < {stru} as former::EntityToStorage >::Storage >, + Definition : former::FormerDefinition< Storage = < {item} as former::EntityToStorage >::Storage >, {{ #[ inline( always ) ] pub fn {field_ident}( self, name : &str ) -> {0}AsSubformer< Self, impl {0}AsSubformerEnd< Self > > @@ -1309,17 +1333,17 @@ where let about = format! ( r#"derive : Former -structure : {stru} +item : {item} field : {field_ident}"#, ); - diag::report_print( about, original_input, hint ); + diag::report_print( about, original_input, debug ); } let doc = format! ( r#" -Represents the endpoint for the forming process of a scalar field managed by a subformer within a `{stru}` entity. +Represents the endpoint for the forming process of a scalar field managed by a subformer within a `{item}` entity. This structure is a critical component of the forming process when using a subform scalar setter. It handles the finalization of the scalar field's value that has been configured through its dedicated subformer. @@ -1327,13 +1351,13 @@ Essentially, this end action integrates the individually formed scalar value bac ## Type Parameters -- `Definition`: The type that defines the former setup for the `{stru}` entity, influencing storage and behavior during forming. +- `Definition`: The type that defines the former setup for the `{item}` entity, influencing storage and behavior during forming. ## Parameters of `call` - `substorage`: Storage type specific to the `{0}`, containing the newly formed scalar value. - `super_former`: An optional context of the `{former}`, which will receive the value. The function ensures - that this context is not `None` and inserts the formed value into the designated field within `{stru}`'s storage. + that this context is not `None` and inserts the formed value into the designated field within `{item}`'s storage. "#, format!( "{}", qt!{ #field_typ } ), @@ -1366,7 +1390,7 @@ Essentially, this end action integrates the individually formed scalar value bac where Definition : former::FormerDefinition < - Storage = < #stru < #struct_generics_ty > as former::EntityToStorage >::Storage, + Storage = < #item < #struct_generics_ty > as former::EntityToStorage >::Storage, >, Types2 : former::FormerDefinitionTypes < diff --git a/module/core/former_meta/src/derive_former/field_attrs.rs b/module/core/former_meta/src/derive_former/field_attrs.rs index a4f7a1357f..0dd3cf3edc 100644 --- a/module/core/former_meta/src/derive_former/field_attrs.rs +++ b/module/core/former_meta/src/derive_former/field_attrs.rs @@ -3,15 +3,14 @@ use super::*; use macro_tools:: { - attr, Result, AttributeComponent, AttributePropertyComponent, - AttributePropertyBoolean, AttributePropertyOptionalBoolean, AttributePropertyOptionalSyn, + AttributePropertyOptionalSingletone, }; -use former_types::{ ComponentAssign }; +use former_types::{ Assign, OptionExt }; /// /// Attributes of a field. @@ -87,11 +86,12 @@ impl FieldAttributes let key_ident = attr.path().get_ident().ok_or_else( || error( attr ) )?; let key_str = format!( "{}", key_ident ); - // Skip standard attributes - if attr::is_standard( &key_str ) - { - continue; - } + // // Skip standard attributes + // if attr::is_standard( &key_str ) + // { + // continue; + // } + // attributes does not have to be known // Match the attribute key and assign to the appropriate field match key_str.as_ref() @@ -101,8 +101,10 @@ impl FieldAttributes AttributeSubformScalarSetter::KEYWORD => result.assign( AttributeSubformScalarSetter::from_meta( attr )? ), AttributeSubformCollectionSetter::KEYWORD => result.assign( AttributeSubformCollectionSetter::from_meta( attr )? ), AttributeSubformEntrySetter::KEYWORD => result.assign( AttributeSubformEntrySetter::from_meta( attr )? ), - "debug" => {} - _ => return Err( error( attr ) ), + "debug" => {}, + _ => {}, + // _ => return Err( error( attr ) ), + // attributes does not have to be known } } @@ -149,25 +151,39 @@ impl AttributeComponent for AttributeConfig } -impl< IntoT > ComponentAssign< AttributeConfig, IntoT > for FieldAttributes +impl< IntoT > Assign< AttributeConfig, IntoT > for FieldAttributes +where + IntoT : Into< AttributeConfig >, +{ + #[ inline( always ) ] + fn assign( &mut self, component : IntoT ) + { + let component : AttributeConfig = component.into(); + self.config.option_assign( component ); + } +} + +impl< IntoT > Assign< AttributeConfig, IntoT > for AttributeConfig where IntoT : Into< AttributeConfig >, { #[ inline( always ) ] fn assign( &mut self, component : IntoT ) { - self.config = Some( component.into() ); + let component = component.into(); + self.default.assign( component.default ); } } -impl< IntoT > ComponentAssign< AttributePropertyDefault, IntoT > for AttributeConfig +impl< IntoT > Assign< AttributePropertyDefault, IntoT > for AttributeConfig where IntoT : Into< AttributePropertyDefault >, { #[ inline( always ) ] fn assign( &mut self, component : IntoT ) { - self.default = component.into(); + // panic!( "" ); + self.default.assign( component.into() ); } } @@ -202,8 +218,6 @@ impl syn::parse::Parse for AttributeConfig if lookahead.peek( syn::Ident ) { let ident : syn::Ident = input.parse()?; - - input.parse::< syn::Token![=] >()?; match ident.to_string().as_str() { AttributePropertyDefault::KEYWORD => result.assign( AttributePropertyDefault::parse( input )? ), @@ -235,7 +249,7 @@ pub struct AttributeScalarSetter pub setter : AttributePropertySetter, /// Specifies whether to provide a sketch of the subform setter as a hint. /// Defaults to `false`, which means no hint is provided unless explicitly requested. - pub hint : AttributePropertyHint, + pub debug : AttributePropertyDebug, } impl AttributeScalarSetter @@ -273,18 +287,33 @@ impl AttributeComponent for AttributeScalarSetter } -impl< IntoT > ComponentAssign< AttributeScalarSetter, IntoT > for FieldAttributes +impl< IntoT > Assign< AttributeScalarSetter, IntoT > for FieldAttributes where IntoT : Into< AttributeScalarSetter >, { #[ inline( always ) ] fn assign( &mut self, component : IntoT ) { - self.scalar = Some( component.into() ); + let component = component.into(); + self.scalar.option_assign( component ); } } -impl< IntoT > ComponentAssign< AttributePropertyName, IntoT > for AttributeScalarSetter +impl< IntoT > Assign< AttributeScalarSetter, IntoT > for AttributeScalarSetter +where + IntoT : Into< AttributeScalarSetter >, +{ + #[ inline( always ) ] + fn assign( &mut self, component : IntoT ) + { + let component = component.into(); + self.name.assign( component.name ); + self.setter.assign( component.setter ); + self.debug.assign( component.debug ); + } +} + +impl< IntoT > Assign< AttributePropertyName, IntoT > for AttributeScalarSetter where IntoT : Into< AttributePropertyName >, { @@ -295,7 +324,7 @@ where } } -impl< IntoT > ComponentAssign< AttributePropertySetter, IntoT > for AttributeScalarSetter +impl< IntoT > Assign< AttributePropertySetter, IntoT > for AttributeScalarSetter where IntoT : Into< AttributePropertySetter >, { @@ -306,14 +335,14 @@ where } } -impl< IntoT > ComponentAssign< AttributePropertyHint, IntoT > for AttributeScalarSetter +impl< IntoT > Assign< AttributePropertyDebug, IntoT > for AttributeScalarSetter where - IntoT : Into< AttributePropertyHint >, + IntoT : Into< AttributePropertyDebug >, { #[ inline( always ) ] fn assign( &mut self, component : IntoT ) { - self.hint = component.into(); + self.debug = component.into(); } } @@ -330,13 +359,13 @@ impl syn::parse::Parse for AttributeScalarSetter "Known entries of attribute ", AttributeScalarSetter::KEYWORD, " are : ", AttributePropertyName::KEYWORD, ", ", AttributePropertySetter::KEYWORD, - ", ", AttributePropertyHint::KEYWORD, + ", ", AttributePropertyDebug::KEYWORD, ".", ); syn_err! ( ident, - r#"Expects an attribute of format '#[ scalar( name = myName, setter = true, hint = false ) ]' + r#"Expects an attribute of format '#[ scalar( name = myName, setter = true ) ]' {known} But got: '{}' "#, @@ -350,13 +379,11 @@ impl syn::parse::Parse for AttributeScalarSetter if lookahead.peek( syn::Ident ) { let ident : syn::Ident = input.parse()?; - - input.parse::< syn::Token![=] >()?; match ident.to_string().as_str() { AttributePropertyName::KEYWORD => result.assign( AttributePropertyName::parse( input )? ), AttributePropertySetter::KEYWORD => result.assign( AttributePropertySetter::parse( input )? ), - AttributePropertyHint::KEYWORD => result.assign( AttributePropertyHint::parse( input )? ), + AttributePropertyDebug::KEYWORD => result.assign( AttributePropertyDebug::from( true ) ), _ => return Err( error( &ident ) ), } } @@ -398,7 +425,7 @@ pub struct AttributeSubformScalarSetter pub setter : AttributePropertySetter, /// Specifies whether to provide a sketch of the subform setter as a hint. /// Defaults to `false`, which means no hint is provided unless explicitly requested. - pub hint : AttributePropertyHint, + pub debug : AttributePropertyDebug, } impl AttributeSubformScalarSetter @@ -435,18 +462,33 @@ impl AttributeComponent for AttributeSubformScalarSetter } -impl< IntoT > ComponentAssign< AttributeSubformScalarSetter, IntoT > for FieldAttributes +impl< IntoT > Assign< AttributeSubformScalarSetter, IntoT > for FieldAttributes where IntoT : Into< AttributeSubformScalarSetter >, { #[ inline( always ) ] fn assign( &mut self, component : IntoT ) { - self.subform_scalar = Some( component.into() ); + let component = component.into(); + self.subform_scalar.option_assign( component ); } } -impl< IntoT > ComponentAssign< AttributePropertyName, IntoT > for AttributeSubformScalarSetter +impl< IntoT > Assign< AttributeSubformScalarSetter, IntoT > for AttributeSubformScalarSetter +where + IntoT : Into< AttributeSubformScalarSetter >, +{ + #[ inline( always ) ] + fn assign( &mut self, component : IntoT ) + { + let component = component.into(); + self.name.assign( component.name ); + self.setter.assign( component.setter ); + self.debug.assign( component.debug ); + } +} + +impl< IntoT > Assign< AttributePropertyName, IntoT > for AttributeSubformScalarSetter where IntoT : Into< AttributePropertyName >, { @@ -457,7 +499,7 @@ where } } -impl< IntoT > ComponentAssign< AttributePropertySetter, IntoT > for AttributeSubformScalarSetter +impl< IntoT > Assign< AttributePropertySetter, IntoT > for AttributeSubformScalarSetter where IntoT : Into< AttributePropertySetter >, { @@ -468,14 +510,14 @@ where } } -impl< IntoT > ComponentAssign< AttributePropertyHint, IntoT > for AttributeSubformScalarSetter +impl< IntoT > Assign< AttributePropertyDebug, IntoT > for AttributeSubformScalarSetter where - IntoT : Into< AttributePropertyHint >, + IntoT : Into< AttributePropertyDebug >, { #[ inline( always ) ] fn assign( &mut self, component : IntoT ) { - self.hint = component.into(); + self.debug = component.into(); } } @@ -492,13 +534,13 @@ impl syn::parse::Parse for AttributeSubformScalarSetter "Known entries of attribute ", AttributeSubformScalarSetter::KEYWORD, " are : ", AttributePropertyName::KEYWORD, ", ", AttributePropertySetter::KEYWORD, - ", ", AttributePropertyHint::KEYWORD, + ", ", AttributePropertyDebug::KEYWORD, ".", ); syn_err! ( ident, - r#"Expects an attribute of format '#[ subform_scalar( name = myName, setter = true, hint = false ) ]' + r#"Expects an attribute of format '#[ subform_scalar( name = myName, setter = true ) ]' {known} But got: '{}' "#, @@ -512,13 +554,11 @@ impl syn::parse::Parse for AttributeSubformScalarSetter if lookahead.peek( syn::Ident ) { let ident : syn::Ident = input.parse()?; - - input.parse::< syn::Token![=] >()?; match ident.to_string().as_str() { AttributePropertyName::KEYWORD => result.assign( AttributePropertyName::parse( input )? ), AttributePropertySetter::KEYWORD => result.assign( AttributePropertySetter::parse( input )? ), - AttributePropertyHint::KEYWORD => result.assign( AttributePropertyHint::parse( input )? ), + AttributePropertyDebug::KEYWORD => result.assign( AttributePropertyDebug::from( true ) ), _ => return Err( error( &ident ) ), } } @@ -538,61 +578,6 @@ impl syn::parse::Parse for AttributeSubformScalarSetter } } -// impl syn::parse::Parse for AttributeSubformScalarSetter -// { -// fn parse( input : syn::parse::ParseStream< '_ > ) -> syn::Result< Self > -// { -// let mut name : Option< syn::Ident > = None; -// let mut setter : Option< bool > = None; -// let mut hint = false; -// -// while !input.is_empty() -// { -// let lookahead = input.lookahead1(); -// if lookahead.peek( syn::Ident ) -// { -// let ident : syn::Ident = input.parse()?; -// match ident.to_string().as_str() -// { -// "name" => -// { -// input.parse::< syn::Token![ = ] >()?; -// name = Some( input.parse()? ); -// } -// "setter" => -// { -// input.parse::< syn::Token![ = ] >()?; -// let value : syn::LitBool = input.parse()?; -// setter = Some( value.value() ); -// } -// "hint" => -// { -// input.parse::< syn::Token![ = ] >()?; -// let value : syn::LitBool = input.parse()?; -// hint = value.value; -// } -// _ => -// { -// return Err( syn::Error::new_spanned( &ident, format!( "Unexpected identifier '{}'. Expected 'name', 'setter', or 'definition'. For example: `subform_scalar( name = myName, setter = true )`", ident ) ) ); -// } -// } -// } -// else -// { -// return Err( syn::Error::new( input.span(), "Expected 'name', 'setter', or 'definition' identifier. For example: `subform_scalar( name = myName, setter = true )`" ) ); -// } -// -// // Optional comma handling -// if input.peek( syn::Token![ , ] ) -// { -// input.parse::< syn::Token![ , ] >()?; -// } -// } -// -// Ok( Self { name : name.into(), setter : setter.into(), hint : hint.into() } ) -// } -// } - /// Represents an attribute for configuring collection setter generation. /// /// This struct is part of a meta-programming approach to enable detailed configuration of nested structs or collections such as `Vec< E >, HashMap< K, E >` and so on. @@ -615,7 +600,7 @@ pub struct AttributeSubformCollectionSetter pub setter : AttributePropertySetter, /// Specifies whether to provide a sketch of the subform setter as a hint. /// Defaults to `false`, which means no hint is provided unless explicitly requested. - pub hint : AttributePropertyHint, + pub debug : AttributePropertyDebug, /// Definition of the collection former to use, e.g., `former::VectorFormer`. pub definition : AttributePropertyDefinition, } @@ -654,18 +639,34 @@ impl AttributeComponent for AttributeSubformCollectionSetter } -impl< IntoT > ComponentAssign< AttributeSubformCollectionSetter, IntoT > for FieldAttributes +impl< IntoT > Assign< AttributeSubformCollectionSetter, IntoT > for FieldAttributes +where + IntoT : Into< AttributeSubformCollectionSetter >, +{ + #[ inline( always ) ] + fn assign( &mut self, component : IntoT ) + { + let component = component.into(); + self.subform_collection.option_assign( component ); + } +} + +impl< IntoT > Assign< AttributeSubformCollectionSetter, IntoT > for AttributeSubformCollectionSetter where IntoT : Into< AttributeSubformCollectionSetter >, { #[ inline( always ) ] fn assign( &mut self, component : IntoT ) { - self.subform_collection = Some( component.into() ); + let component = component.into(); + self.name.assign( component.name ); + self.setter.assign( component.setter ); + self.debug.assign( component.debug ); + self.definition.assign( component.definition ); } } -impl< IntoT > ComponentAssign< AttributePropertyName, IntoT > for AttributeSubformCollectionSetter +impl< IntoT > Assign< AttributePropertyName, IntoT > for AttributeSubformCollectionSetter where IntoT : Into< AttributePropertyName >, { @@ -676,7 +677,7 @@ where } } -impl< IntoT > ComponentAssign< AttributePropertySetter, IntoT > for AttributeSubformCollectionSetter +impl< IntoT > Assign< AttributePropertySetter, IntoT > for AttributeSubformCollectionSetter where IntoT : Into< AttributePropertySetter >, { @@ -687,7 +688,7 @@ where } } -impl< IntoT > ComponentAssign< AttributePropertyDefinition, IntoT > for AttributeSubformCollectionSetter +impl< IntoT > Assign< AttributePropertyDefinition, IntoT > for AttributeSubformCollectionSetter where IntoT : Into< AttributePropertyDefinition >, { @@ -698,14 +699,14 @@ where } } -impl< IntoT > ComponentAssign< AttributePropertyHint, IntoT > for AttributeSubformCollectionSetter +impl< IntoT > Assign< AttributePropertyDebug, IntoT > for AttributeSubformCollectionSetter where - IntoT : Into< AttributePropertyHint >, + IntoT : Into< AttributePropertyDebug >, { #[ inline( always ) ] fn assign( &mut self, component : IntoT ) { - self.hint = component.into(); + self.debug = component.into(); } } @@ -722,14 +723,14 @@ impl syn::parse::Parse for AttributeSubformCollectionSetter "Known entries of attribute ", AttributeSubformCollectionSetter::KEYWORD, " are : ", AttributePropertyName::KEYWORD, ", ", AttributePropertySetter::KEYWORD, - ", ", AttributePropertyHint::KEYWORD, + ", ", AttributePropertyDebug::KEYWORD, ", ", AttributePropertyDefinition::KEYWORD, ".", ); syn_err! ( ident, - r#"Expects an attribute of format '#[ subform_collection( name = myName, setter = true, hint = false, definition = MyDefinition ) ]' + r#"Expects an attribute of format '#[ subform_collection( name = myName, setter = true, debug, definition = MyDefinition ) ]' {known} But got: '{}' "#, @@ -743,13 +744,11 @@ impl syn::parse::Parse for AttributeSubformCollectionSetter if lookahead.peek( syn::Ident ) { let ident : syn::Ident = input.parse()?; - - input.parse::< syn::Token![=] >()?; match ident.to_string().as_str() { AttributePropertyName::KEYWORD => result.assign( AttributePropertyName::parse( input )? ), AttributePropertySetter::KEYWORD => result.assign( AttributePropertySetter::parse( input )? ), - AttributePropertyHint::KEYWORD => result.assign( AttributePropertyHint::parse( input )? ), + AttributePropertyDebug::KEYWORD => result.assign( AttributePropertyDebug::from( true ) ), AttributePropertyDefinition::KEYWORD => result.assign( AttributePropertyDefinition::parse( input )? ), _ => return Err( error( &ident ) ), } @@ -799,7 +798,7 @@ pub struct AttributeSubformEntrySetter pub setter : AttributePropertySetter, /// Specifies whether to provide a sketch of the subform setter as a hint. /// Defaults to `false`, which means no hint is provided unless explicitly requested. - pub hint : AttributePropertyHint, + pub debug : AttributePropertyDebug, } impl AttributeSubformEntrySetter @@ -836,18 +835,33 @@ impl AttributeComponent for AttributeSubformEntrySetter } -impl< IntoT > ComponentAssign< AttributeSubformEntrySetter, IntoT > for FieldAttributes +impl< IntoT > Assign< AttributeSubformEntrySetter, IntoT > for FieldAttributes where IntoT : Into< AttributeSubformEntrySetter >, { #[ inline( always ) ] fn assign( &mut self, component : IntoT ) { - self.subform_entry = Some( component.into() ); + let component = component.into(); + self.subform_entry.option_assign( component ); } } -impl< IntoT > ComponentAssign< AttributePropertyName, IntoT > for AttributeSubformEntrySetter +impl< IntoT > Assign< AttributeSubformEntrySetter, IntoT > for AttributeSubformEntrySetter +where + IntoT : Into< AttributeSubformEntrySetter >, +{ + #[ inline( always ) ] + fn assign( &mut self, component : IntoT ) + { + let component = component.into(); + self.name.assign( component.name ); + self.setter.assign( component.setter ); + self.debug.assign( component.debug ); + } +} + +impl< IntoT > Assign< AttributePropertyName, IntoT > for AttributeSubformEntrySetter where IntoT : Into< AttributePropertyName >, { @@ -858,7 +872,7 @@ where } } -impl< IntoT > ComponentAssign< AttributePropertySetter, IntoT > for AttributeSubformEntrySetter +impl< IntoT > Assign< AttributePropertySetter, IntoT > for AttributeSubformEntrySetter where IntoT : Into< AttributePropertySetter >, { @@ -869,14 +883,14 @@ where } } -impl< IntoT > ComponentAssign< AttributePropertyHint, IntoT > for AttributeSubformEntrySetter +impl< IntoT > Assign< AttributePropertyDebug, IntoT > for AttributeSubformEntrySetter where - IntoT : Into< AttributePropertyHint >, + IntoT : Into< AttributePropertyDebug >, { #[ inline( always ) ] fn assign( &mut self, component : IntoT ) { - self.hint = component.into(); + self.debug = component.into(); } } @@ -893,7 +907,7 @@ impl syn::parse::Parse for AttributeSubformEntrySetter "Known entries of attribute ", AttributeSubformEntrySetter::KEYWORD, " are : ", AttributePropertyName::KEYWORD, ", ", AttributePropertySetter::KEYWORD, - ", ", AttributePropertyHint::KEYWORD, + ", ", AttributePropertyDebug::KEYWORD, ".", ); syn_err! @@ -913,13 +927,11 @@ impl syn::parse::Parse for AttributeSubformEntrySetter if lookahead.peek( syn::Ident ) { let ident : syn::Ident = input.parse()?; - - input.parse::< syn::Token![=] >()?; match ident.to_string().as_str() { AttributePropertyName::KEYWORD => result.assign( AttributePropertyName::parse( input )? ), AttributePropertySetter::KEYWORD => result.assign( AttributePropertySetter::parse( input )? ), - AttributePropertyHint::KEYWORD => result.assign( AttributePropertyHint::parse( input )? ), + AttributePropertyDebug::KEYWORD => result.assign( AttributePropertyDebug::from( true ) ), _ => return Err( error( &ident ) ), } } @@ -946,76 +958,76 @@ impl syn::parse::Parse for AttributeSubformEntrySetter /// Marker type for attribute property to specify whether to provide a sketch as a hint. /// Defaults to `false`, which means no hint is provided unless explicitly requested. #[ derive( Debug, Default, Clone, Copy ) ] -pub struct AttributePropertyHintMarker; +pub struct DebugMarker; /// Specifies whether to provide a sketch as a hint. /// Defaults to `false`, which means no hint is provided unless explicitly requested. -impl AttributePropertyComponent for AttributePropertyHintMarker +impl AttributePropertyComponent for DebugMarker { - const KEYWORD : &'static str = "hint"; + const KEYWORD : &'static str = "debug"; } /// Specifies whether to provide a sketch as a hint. /// Defaults to `false`, which means no hint is provided unless explicitly requested. -pub type AttributePropertyHint = AttributePropertyBoolean< AttributePropertyHintMarker >; +pub type AttributePropertyDebug = AttributePropertyOptionalSingletone< DebugMarker >; // = /// Disable generation of setter. /// Attributes still might generate some helper methods to reuse by custom setter. #[ derive( Debug, Default, Clone, Copy ) ] -pub struct AttributePropertySetterMarker; +pub struct SetterMarker; -impl AttributePropertyComponent for AttributePropertySetterMarker +impl AttributePropertyComponent for SetterMarker { const KEYWORD : &'static str = "setter"; } /// Disable generation of setter. /// Attributes still might generate some helper methods to reuse by custom setter. -pub type AttributePropertySetter = AttributePropertyOptionalBoolean< AttributePropertySetterMarker >; +pub type AttributePropertySetter = AttributePropertyOptionalBoolean< SetterMarker >; // = /// Marker type for attribute property of optional identifier that names the setter. It is parsed from inputs /// like `name = my_field`. #[ derive( Debug, Default, Clone, Copy ) ] -pub struct AttributePropertyNameMarker; +pub struct NameMarker; -impl AttributePropertyComponent for AttributePropertyNameMarker +impl AttributePropertyComponent for NameMarker { const KEYWORD : &'static str = "name"; } /// An optional identifier that names the setter. It is parsed from inputs /// like `name = my_field`. -pub type AttributePropertyName = AttributePropertyOptionalSyn< syn::Ident, AttributePropertyNameMarker >; +pub type AttributePropertyName = AttributePropertyOptionalSyn< syn::Ident, NameMarker >; // = /// Marker type for default value to use for a field. #[ derive( Debug, Default, Clone, Copy ) ] -pub struct AttributePropertyDefaultMarker; +pub struct DefaultMarker; -impl AttributePropertyComponent for AttributePropertyDefaultMarker +impl AttributePropertyComponent for DefaultMarker { const KEYWORD : &'static str = "default"; } /// An optional identifier that names the setter. It is parsed from inputs /// like `name = my_field`. -pub type AttributePropertyDefault = AttributePropertyOptionalSyn< syn::Expr, AttributePropertyDefaultMarker >; +pub type AttributePropertyDefault = AttributePropertyOptionalSyn< syn::Expr, DefaultMarker >; // = /// Marker type for definition of the collection former to use, e.g., `former::VectorFormer`. #[ derive( Debug, Default, Clone, Copy ) ] -pub struct AttributePropertyDefinitionMarker; +pub struct DefinitionMarker; -impl AttributePropertyComponent for AttributePropertyDefinitionMarker +impl AttributePropertyComponent for DefinitionMarker { const KEYWORD : &'static str = "definition"; } /// Definition of the collection former to use, e.g., `former::VectorFormer`. -pub type AttributePropertyDefinition = AttributePropertyOptionalSyn< syn::Type, AttributePropertyDefinitionMarker >; +pub type AttributePropertyDefinition = AttributePropertyOptionalSyn< syn::Type, DefinitionMarker >; 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 73e11f9cb0..44e8273292 100644 --- a/module/core/former_meta/src/derive_former/struct_attrs.rs +++ b/module/core/former_meta/src/derive_former/struct_attrs.rs @@ -1,22 +1,23 @@ +//! //! Attributes of the whole item. +//! use super::*; use macro_tools:: { - attr, Result, AttributeComponent, AttributePropertyComponent, - AttributePropertyBoolean, + AttributePropertyOptionalSingletone, }; -use former_types::{ ComponentAssign }; +use former_types::{ Assign, OptionExt }; /// Represents the attributes of a struct, including storage fields, mutator, and perform attributes. #[ derive( Debug, Default ) ] -pub struct StructAttributes +pub struct ItemAttributes { /// Optional attribute for storage-specific fields. /// This field is used to specify fields that should be part of the storage but not the final formed structure. @@ -31,7 +32,7 @@ pub struct StructAttributes pub perform : Option< AttributePerform >, } -impl StructAttributes +impl ItemAttributes { pub fn from_attrs< 'a >( attrs : impl Iterator< Item = &'a syn::Attribute > ) -> Result< Self > @@ -63,10 +64,11 @@ impl StructAttributes let key_ident = attr.path().get_ident().ok_or_else( || error( attr ) )?; let key_str = format!( "{}", key_ident ); - if attr::is_standard( &key_str ) - { - continue; - } + // attributes does not have to be known + // if attr::is_standard( &key_str ) + // { + // continue; + // } match key_str.as_ref() { @@ -74,57 +76,15 @@ impl StructAttributes AttributeMutator::KEYWORD => result.assign( AttributeMutator::from_meta( attr )? ), AttributePerform::KEYWORD => result.assign( AttributePerform::from_meta( attr )? ), "debug" => {} - _ => return Err( error( attr ) ), + _ => {}, + // _ => return Err( error( attr ) ), + // attributes does not have to be known } } Ok( result ) } -// pub fn from_attrs< 'a >( attrs : impl Iterator< Item = &'a syn::Attribute > ) -> Result< Self > -// { -// let mut storage_fields = None; -// let mut mutator : AttributeMutator = Default::default(); -// let mut perform = None; -// -// for attr in attrs -// { -// let key_ident = attr.path().get_ident() -// .ok_or_else( || syn_err!( attr, "Expects an attribute of format #[ attribute( key1 = val1, key2 = val2 ) ], but got:\n {}", qt!{ #attr } ) )?; -// let key_str = format!( "{}", key_ident ); -// -// if attr::is_standard( &key_str ) -// { -// continue; -// } -// -// match key_str.as_ref() -// { -// AttributeStorageFields::KEYWORD => -// { -// storage_fields.replace( AttributeStorageFields::from_meta( attr )? ); -// } -// AttributeMutator::KEYWORD => -// { -// mutator = AttributeMutator::from_meta( attr )?; -// } -// AttributePerform::KEYWORD => -// { -// perform.replace( AttributePerform::from_meta( attr )? ); -// } -// "debug" => -// { -// } -// _ => -// { -// return Err( syn_err!( attr, "Known structure attirbutes are : `storage_fields`, `mutator`, `perform`, `debug`.\nUnknown structure attribute : {}", qt!{ #attr } ) ); -// } -// } -// } -// -// Ok( StructAttributes { perform, storage_fields, mutator } ) -// } - /// /// Generate parts, used for generating `perform()`` method. /// @@ -238,14 +198,27 @@ impl AttributeComponent for AttributeStorageFields } -impl< IntoT > ComponentAssign< AttributeStorageFields, IntoT > for StructAttributes +impl< IntoT > Assign< AttributeStorageFields, IntoT > for ItemAttributes +where + IntoT : Into< AttributeStorageFields >, +{ + #[ inline( always ) ] + fn assign( &mut self, component : IntoT ) + { + let component = component.into(); + self.storage_fields.option_assign( component ); + } +} + +impl< IntoT > Assign< AttributeStorageFields, IntoT > for AttributeStorageFields where IntoT : Into< AttributeStorageFields >, { #[ inline( always ) ] fn assign( &mut self, component : IntoT ) { - self.storage_fields = Some( component.into() ); + let component = component.into(); + self.fields = component.fields; } } @@ -272,7 +245,7 @@ impl syn::parse::Parse for AttributeStorageFields /// /// ## Example of code /// ```ignore -/// custom = true, hint = true +/// custom, debug /// ``` #[ derive( Debug, Default ) ] @@ -283,7 +256,7 @@ pub struct AttributeMutator pub custom : AttributePropertyCustom, /// Specifies whether to provide a sketch of the mutator as a hint. /// Defaults to `false`, which means no hint is provided unless explicitly requested. - pub hint : AttributePropertyHint, + pub debug : AttributePropertyDebug, } impl AttributeComponent for AttributeMutator @@ -302,35 +275,49 @@ impl AttributeComponent for AttributeMutator { return Ok( Default::default() ) }, - _ => return_syn_err!( attr, "Expects an attribute of format `#[ mutator( custom = true, hint = true ) ]`. \nGot: {}", qt!{ #attr } ), + _ => return_syn_err!( attr, "Expects an attribute of format `#[ mutator( custom ) ]`. \nGot: {}", qt!{ #attr } ), } } } -impl< IntoT > ComponentAssign< AttributeMutator, IntoT > for StructAttributes +impl< IntoT > Assign< AttributeMutator, IntoT > for ItemAttributes where IntoT : Into< AttributeMutator >, { #[ inline( always ) ] fn assign( &mut self, component : IntoT ) { - self.mutator = component.into(); + let component = component.into(); + self.mutator.assign( component ); } } -impl< IntoT > ComponentAssign< AttributePropertyHint, IntoT > for AttributeMutator +impl< IntoT > Assign< AttributeMutator, IntoT > for AttributeMutator where - IntoT : Into< AttributePropertyHint >, + IntoT : Into< AttributeMutator >, { #[ inline( always ) ] fn assign( &mut self, component : IntoT ) { - self.hint = component.into(); + let component = component.into(); + self.custom.assign( component.custom ); + self.debug.assign( component.debug ); } } -impl< IntoT > ComponentAssign< AttributePropertyCustom, IntoT > for AttributeMutator +impl< IntoT > Assign< AttributePropertyDebug, IntoT > for AttributeMutator +where + IntoT : Into< AttributePropertyDebug >, +{ + #[ inline( always ) ] + fn assign( &mut self, component : IntoT ) + { + self.debug = component.into(); + } +} + +impl< IntoT > Assign< AttributePropertyCustom, IntoT > for AttributeMutator where IntoT : Into< AttributePropertyCustom >, { @@ -353,13 +340,13 @@ impl syn::parse::Parse for AttributeMutator ( "Known entries of attribute ", AttributeMutator::KEYWORD, " are : ", AttributePropertyCustom::KEYWORD, - ", ", AttributePropertyHint::KEYWORD, + ", ", AttributePropertyDebug::KEYWORD, ".", ); syn_err! ( ident, - r#"Expects an attribute of format '#[ mutator( custom = false, hint = false ) ]' + r#"Expects an attribute of format '#[ mutator( custom ) ]' {known} But got: '{}' "#, @@ -373,12 +360,10 @@ impl syn::parse::Parse for AttributeMutator if lookahead.peek( syn::Ident ) { let ident : syn::Ident = input.parse()?; - - input.parse::< syn::Token![=] >()?; match ident.to_string().as_str() { - AttributePropertyCustom::KEYWORD => result.assign( AttributePropertyCustom::parse( input )? ), - AttributePropertyHint::KEYWORD => result.assign( AttributePropertyHint::parse( input )? ), + AttributePropertyCustom::KEYWORD => result.assign( AttributePropertyCustom::from( true ) ), + AttributePropertyDebug::KEYWORD => result.assign( AttributePropertyDebug::from( true ) ), _ => return Err( error( &ident ) ), } } @@ -441,14 +426,27 @@ impl syn::parse::Parse for AttributePerform } } -impl< IntoT > ComponentAssign< AttributePerform, IntoT > for StructAttributes +impl< IntoT > Assign< AttributePerform, IntoT > for ItemAttributes +where + IntoT : Into< AttributePerform >, +{ + #[ inline( always ) ] + fn assign( &mut self, component : IntoT ) + { + let component = component.into(); + self.perform.option_assign( component ); + } +} + +impl< IntoT > Assign< AttributePerform, IntoT > for AttributePerform where IntoT : Into< AttributePerform >, { #[ inline( always ) ] fn assign( &mut self, component : IntoT ) { - self.perform = Some( component.into() ); + let component = component.into(); + self.signature = component.signature; } } @@ -457,29 +455,29 @@ where /// Marker type for attribute property to specify whether to provide a sketch as a hint. /// Defaults to `false`, which means no hint is provided unless explicitly requested. #[ derive( Debug, Default, Clone, Copy ) ] -pub struct AttributePropertyHintMarker; +pub struct DebugMarker; -impl AttributePropertyComponent for AttributePropertyHintMarker +impl AttributePropertyComponent for DebugMarker { - const KEYWORD : &'static str = "hint"; + const KEYWORD : &'static str = "debug"; } /// Specifies whether to provide a sketch as a hint. /// Defaults to `false`, which means no hint is provided unless explicitly requested. -pub type AttributePropertyHint = AttributePropertyBoolean< AttributePropertyHintMarker >; +pub type AttributePropertyDebug = AttributePropertyOptionalSingletone< DebugMarker >; // = /// Marker type for attribute property to indicates whether a custom code should be generated. /// Defaults to `false`, meaning no custom code is generated unless explicitly requested. #[ derive( Debug, Default, Clone, Copy ) ] -pub struct AttributePropertyCustomMarker; +pub struct CustomMarker; -impl AttributePropertyComponent for AttributePropertyCustomMarker +impl AttributePropertyComponent for CustomMarker { const KEYWORD : &'static str = "custom"; } /// Indicates whether a custom code should be generated. /// Defaults to `false`, meaning no custom code is generated unless explicitly requested. -pub type AttributePropertyCustom = AttributePropertyBoolean< AttributePropertyCustomMarker >; +pub type AttributePropertyCustom = AttributePropertyOptionalSingletone< CustomMarker >; diff --git a/module/core/former_meta/src/lib.rs b/module/core/former_meta/src/lib.rs index e9d2e50279..3a4d6af4d0 100644 --- a/module/core/former_meta/src/lib.rs +++ b/module/core/former_meta/src/lib.rs @@ -170,10 +170,10 @@ pub fn component_from( input : proc_macro::TokenStream ) -> proc_macro::TokenStr } } -/// Derives the `ComponentAssign` trait for struct fields, allowing each field to be set +/// Derives the `Assign` trait for struct fields, allowing each field to be set /// with a value that can be converted into the field's type. /// -/// This macro facilitates the automatic implementation of the `ComponentAssign` trait for all +/// This macro facilitates the automatic implementation of the `Assign` trait for all /// fields within a struct, leveraging the power of Rust's type system to ensure type safety /// and conversion logic. It is particularly useful for builder patterns or mutating instances /// of data structures in a fluent and ergonomic manner. @@ -188,12 +188,12 @@ pub fn component_from( input : proc_macro::TokenStream ) -> proc_macro::TokenStr /// /// # Input Code Example /// -/// Given a struct definition annotated with `#[ derive( ComponentAssign ) ]` : +/// Given a struct definition annotated with `#[ derive( Assign ) ]` : /// /// ```rust -/// use former::ComponentAssign; +/// use former::Assign; /// -/// #[ derive( Default, PartialEq, Debug, former::ComponentAssign ) ] +/// #[ derive( Default, PartialEq, Debug, former::Assign ) ] /// struct Person /// { /// age : i32, @@ -211,7 +211,7 @@ pub fn component_from( input : proc_macro::TokenStream ) -> proc_macro::TokenStr /// The procedural macro generates the following implementations for `Person` : /// /// ```rust -/// use former::ComponentAssign; +/// use former::Assign; /// /// #[ derive( Default, PartialEq, Debug ) ] /// struct Person @@ -220,7 +220,7 @@ pub fn component_from( input : proc_macro::TokenStream ) -> proc_macro::TokenStr /// name : String, /// } /// -/// impl< IntoT > ComponentAssign< i32, IntoT > for Person +/// impl< IntoT > Assign< i32, IntoT > for Person /// where /// IntoT : Into< i32 >, /// { @@ -230,7 +230,7 @@ pub fn component_from( input : proc_macro::TokenStream ) -> proc_macro::TokenStr /// } /// } /// -/// impl< IntoT > ComponentAssign< String, IntoT > for Person +/// impl< IntoT > Assign< String, IntoT > for Person /// where /// IntoT : Into< String >, /// { @@ -250,7 +250,7 @@ pub fn component_from( input : proc_macro::TokenStream ) -> proc_macro::TokenStr #[ cfg( feature = "enabled" ) ] #[ cfg( feature = "derive_component_assign" ) ] -#[ proc_macro_derive( ComponentAssign, attributes( debug ) ) ] +#[ proc_macro_derive( Assign, attributes( debug ) ) ] pub fn component_assign( input : proc_macro::TokenStream ) -> proc_macro::TokenStream { let result = component::component_assign::component_assign( input ); @@ -274,7 +274,7 @@ pub fn component_assign( input : proc_macro::TokenStream ) -> proc_macro::TokenS /// # Conditions /// /// - This macro is only enabled when the `derive_components_assign` feature is active in your `Cargo.toml`. -/// - The type must implement `ComponentAssign` (`derive( ComponentAssign )`) +/// - The type must implement `Assign` (`derive( Assign )`) /// /// # Limitations /// This trait cannot be derived, if the struct has fields with identical types @@ -284,9 +284,9 @@ pub fn component_assign( input : proc_macro::TokenStream ) -> proc_macro::TokenS /// An example when we encapsulate parameters passed to a function in a struct. /// /// ```rust -/// use former::{ ComponentAssign, ComponentsAssign }; +/// use former::{ Assign, ComponentsAssign }; /// -/// #[ derive( Default, ComponentAssign, ComponentsAssign ) ] +/// #[ derive( Default, Assign, ComponentsAssign ) ] /// struct BigOpts /// { /// cond : bool, @@ -294,7 +294,7 @@ pub fn component_assign( input : proc_macro::TokenStream ) -> proc_macro::TokenS /// str : String, /// } /// -/// #[ derive( Default, ComponentAssign, ComponentsAssign ) ] +/// #[ derive( Default, Assign, ComponentsAssign ) ] /// struct SmallerOpts /// { /// cond: bool, @@ -343,7 +343,7 @@ pub fn component_assign( input : proc_macro::TokenStream ) -> proc_macro::TokenS /// Which expands approximately into : /// /// ```rust -/// use former::{ ComponentAssign, ComponentsAssign }; +/// use former::{ Assign, ComponentsAssign }; /// /// #[derive(Default)] /// struct BigOpts @@ -353,7 +353,7 @@ pub fn component_assign( input : proc_macro::TokenStream ) -> proc_macro::TokenS /// str : String, /// } /// -/// impl< IntoT > ComponentAssign< bool, IntoT > for BigOpts +/// impl< IntoT > Assign< bool, IntoT > for BigOpts /// where /// IntoT : Into< bool >, /// { @@ -363,7 +363,7 @@ pub fn component_assign( input : proc_macro::TokenStream ) -> proc_macro::TokenS /// } /// } /// -/// impl< IntoT > ComponentAssign< i32, IntoT > for BigOpts +/// impl< IntoT > Assign< i32, IntoT > for BigOpts /// where /// IntoT : Into< i32 >, /// { @@ -373,7 +373,7 @@ pub fn component_assign( input : proc_macro::TokenStream ) -> proc_macro::TokenS /// } /// } /// -/// impl< IntoT > ComponentAssign< String, IntoT > for BigOpts +/// impl< IntoT > Assign< String, IntoT > for BigOpts /// where /// IntoT : Into< String >, /// { @@ -395,9 +395,9 @@ pub fn component_assign( input : proc_macro::TokenStream ) -> proc_macro::TokenS /// /// impl< T, IntoT > BigOptsComponentsAssign< IntoT > for T /// where -/// T : former::ComponentAssign< bool, IntoT >, -/// T : former::ComponentAssign< i32, IntoT >, -/// T : former::ComponentAssign< String, IntoT >, +/// T : former::Assign< bool, IntoT >, +/// T : former::Assign< i32, IntoT >, +/// T : former::Assign< String, IntoT >, /// IntoT : Into< bool >, /// IntoT : Into< i32 >, /// IntoT : Into< String >, @@ -405,9 +405,9 @@ pub fn component_assign( input : proc_macro::TokenStream ) -> proc_macro::TokenS /// { /// fn components_assign( &mut self, component : IntoT ) /// { -/// former::ComponentAssign::< bool, _ >::assign( self, component.clone() ); -/// former::ComponentAssign::< i32, _ >::assign( self, component.clone() ); -/// former::ComponentAssign::< String, _ >::assign( self, component.clone() ); +/// former::Assign::< bool, _ >::assign( self, component.clone() ); +/// former::Assign::< i32, _ >::assign( self, component.clone() ); +/// former::Assign::< String, _ >::assign( self, component.clone() ); /// } /// } /// @@ -418,7 +418,7 @@ pub fn component_assign( input : proc_macro::TokenStream ) -> proc_macro::TokenS /// int : i32, /// } /// -/// impl< IntoT > ComponentAssign< bool, IntoT > for SmallerOpts +/// impl< IntoT > Assign< bool, IntoT > for SmallerOpts /// where /// IntoT : Into< bool >, /// { @@ -428,7 +428,7 @@ pub fn component_assign( input : proc_macro::TokenStream ) -> proc_macro::TokenS /// } /// } /// -/// impl< IntoT > ComponentAssign< i32, IntoT > for SmallerOpts +/// impl< IntoT > Assign< i32, IntoT > for SmallerOpts /// where /// IntoT : Into< i32 >, /// { @@ -449,16 +449,16 @@ pub fn component_assign( input : proc_macro::TokenStream ) -> proc_macro::TokenS /// /// impl< T, IntoT > SmallerOptsComponentsAssign< IntoT > for T /// where -/// T : former::ComponentAssign< bool, IntoT >, -/// T : former::ComponentAssign< i32, IntoT >, +/// T : former::Assign< bool, IntoT >, +/// T : former::Assign< i32, IntoT >, /// IntoT : Into< bool >, /// IntoT : Into< i32 >, /// IntoT : Clone, /// { /// fn smaller_opts_assign( &mut self, component : IntoT ) /// { -/// former::ComponentAssign::< bool, _ >::assign( self, component.clone() ); -/// former::ComponentAssign::< i32, _ >::assign( self, component.clone() ); +/// former::Assign::< bool, _ >::assign( self, component.clone() ); +/// former::Assign::< i32, _ >::assign( self, component.clone() ); /// } /// } /// diff --git a/module/core/former_types/Cargo.toml b/module/core/former_types/Cargo.toml index 95ca657ed3..d6b6ca5fb3 100644 --- a/module/core/former_types/Cargo.toml +++ b/module/core/former_types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "former_types" -version = "2.1.0" +version = "2.2.0" edition = "2021" authors = [ "Kostiantyn Wandalen ", diff --git a/module/core/former_types/Readme.md b/module/core/former_types/Readme.md index 105cb237a2..42346b3bc0 100644 --- a/module/core/former_types/Readme.md +++ b/module/core/former_types/Readme.md @@ -8,12 +8,12 @@ A flexible and extensible implementation of the builder pattern. Its compile-time structures and traits that are not generated but reused. -## Example: Using Trait ComponentAssign +## Example: Using Trait Assign Demonstrates setting various components (fields) of a struct. The `former_types` crate provides a generic interface for setting components on an object. This example defines a `Person` struct -and implements the `ComponentAssign` trait for its fields. It shows how to use these implementations to set the fields of a `Person` +and implements the `Assign` trait for its fields. It shows how to use these implementations to set the fields of a `Person` instance using different types that can be converted into the required types. ```rust @@ -23,7 +23,7 @@ fn main() {} #[ cfg( all( feature = "derive_former", feature = "enabled" ) ) ] fn main() { - use former_types::ComponentAssign; + use former_types::Assign; #[ derive( Default, PartialEq, Debug ) ] struct Person @@ -32,7 +32,7 @@ fn main() name : String, } - impl< IntoT > ComponentAssign< i32, IntoT > for Person + impl< IntoT > Assign< i32, IntoT > for Person where IntoT : Into< i32 >, { @@ -42,7 +42,7 @@ fn main() } } - impl< IntoT > ComponentAssign< String, IntoT > for Person + impl< IntoT > Assign< String, IntoT > for Person where IntoT : Into< String >, { diff --git a/module/core/former_types/examples/former_types_trivial.rs b/module/core/former_types/examples/former_types_trivial.rs index 70d226686d..c379293640 100644 --- a/module/core/former_types/examples/former_types_trivial.rs +++ b/module/core/former_types/examples/former_types_trivial.rs @@ -1,17 +1,17 @@ //! -//! ## Example: Using Trait ComponentAssign +//! ## Example: Using Trait Assign //! //! Demonstrates setting various components (fields) of a struct. //! //! The `former_types` crate provides a generic interface for setting components on an object. This example defines a `Person` struct -//! and implements the `ComponentAssign` trait for its fields. It shows how to use these implementations to set the fields of a `Person` +//! and implements the `Assign` trait for its fields. It shows how to use these implementations to set the fields of a `Person` //! instance using different types that can be converted into the required types. //! //! ## Explanation //! //! - **Person Struct**: The `Person` struct has two fields: `age` (an integer) and `name` (a string). The `Default` and `PartialEq` traits are derived to facilitate default construction and comparison. //! -//! - **ComponentAssign Implementations**: The `ComponentAssign` trait is implemented for the `age` and `name` fields of the `Person` struct. +//! - **Assign Implementations**: The `Assign` trait is implemented for the `age` and `name` fields of the `Person` struct. //! - For `age`: The trait is implemented for any type that can be converted into an `i32`. //! - For `name`: The trait is implemented for any type that can be converted into a `String`. //! @@ -26,7 +26,7 @@ fn main() {} #[ cfg( all( feature = "derive_former", feature = "enabled" ) ) ] fn main() { - use former_types::ComponentAssign; + use former_types::Assign; #[ derive( Default, PartialEq, Debug ) ] struct Person @@ -35,7 +35,7 @@ fn main() name : String, } - impl< IntoT > ComponentAssign< i32, IntoT > for Person + impl< IntoT > Assign< i32, IntoT > for Person where IntoT : Into< i32 >, { @@ -45,7 +45,7 @@ fn main() } } - impl< IntoT > ComponentAssign< String, IntoT > for Person + impl< IntoT > Assign< String, IntoT > for Person where IntoT : Into< String >, { diff --git a/module/core/former_types/src/component.rs b/module/core/former_types/src/component.rs index 68a5479fce..21398497d8 100644 --- a/module/core/former_types/src/component.rs +++ b/module/core/former_types/src/component.rs @@ -1,33 +1,31 @@ - /// Provides a generic interface for setting a component of a certain type on an object. /// /// This trait abstracts the action of setting or replacing a component, where a component /// can be any part or attribute of an object, such as a field value. It is designed to be -/// generic over the type of the component being set ( `T` ) and the type that can be converted -/// into the component ( `IntoT` ). This design allows for flexible implementations that can +/// generic over the type of the component being set (`T`) and the type that can be converted +/// into the component (`IntoT`). This design allows for flexible implementations that can /// accept various types that can then be converted into the required component type. /// /// # Type Parameters /// -/// - `T` : The type of the component to be set on the implementing object. This type represents +/// - `T`: The type of the component to be set on the implementing object. This type represents /// the final form of the component as it should be stored or represented in the object. -/// - `IntoT` : The type that can be converted into `T`. This allows the `set` method to accept +/// - `IntoT`: The type that can be converted into `T`. This allows the `assign` method to accept /// different types that are capable of being transformed into the required component type `T`, /// providing greater flexibility in setting the component. /// /// # Examples /// -/// Implementing `ComponentAssign` to set a name string on a struct : +/// Implementing `Assign` to set a name string on a struct: /// /// ```rust -/// use former_types::ComponentAssign; // use crate `former` instead of crate `former_types` unless you need to use crate `former_types` directly +/// use former_types::Assign; // use crate `former` instead of crate `former_types` unless you need to use crate `former_types` directly /// -/// struct MyStruct -/// { -/// name : String, +/// struct MyStruct { +/// name: String, /// } /// -/// impl< IntoT : Into< String > > ComponentAssign< String, IntoT > for MyStruct +/// impl< IntoT : Into< String > > Assign< String, IntoT > for MyStruct /// { /// fn assign( &mut self, component : IntoT ) /// { @@ -40,42 +38,116 @@ /// assert_eq!( obj.name, "New Name" ); /// ``` #[ cfg( any( feature = "types_component_assign" ) ) ] -pub trait ComponentAssign< T, IntoT > +pub trait Assign< T, IntoT > where IntoT : Into< T >, { /// Sets or replaces the component on the object with the given value. /// - /// This method takes ownership of the given value ( `component` ), which is of type `IntoT`. + /// This method takes ownership of the given value (`component`), which is of type `IntoT`. /// `component` is then converted into type `T` and set as the component of the object. fn assign( &mut self, component : IntoT ); } -/// The `AssignWithType` trait provides a mechanism to set a component on an object, utilizing the type information explicitly. This trait extends the functionality of `SetComponen`t by allowing implementers to specify the component's type at the method call site, enhancing expressiveness in code that manipulates object states. +/// Extension trait to provide a method for setting a component on an `Option` +/// if the `Option` is currently `None`. If the `Option` is `Some`, the method will +/// delegate to the `Assign` trait's `assign` method. +/// +/// # Type Parameters +/// +/// - `T`: The type of the component to be set on the implementing object. This type represents +/// the final form of the component as it should be stored or represented in the object. +/// +/// # Examples +/// +/// Using `option_assign` to set a component on an `Option`: +/// +/// ```rust +/// use former_types::{ Assign, OptionExt }; // use crate `former` instead of crate `former_types` unless you need to use crate `former_types` directly +/// +/// struct MyStruct +/// { +/// name : String, +/// } /// -/// ### Method Detail +/// impl< IntoT : Into< MyStruct > > Assign< MyStruct, IntoT > for MyStruct +/// { +/// fn assign( &mut self, component : IntoT ) +/// { +/// self.name = component.into().name; +/// } +/// } /// -/// - `assign_with_type::< T, IntoT >( &mut self, component : IntoT )` +/// let mut opt_struct: Option< MyStruct > = None; +/// opt_struct.option_assign( MyStruct { name: "New Name".to_string() } ); +/// assert_eq!( opt_struct.unwrap().name, "New Name" ); +/// ``` +#[ cfg( any( feature = "types_component_assign" ) ) ] +pub trait OptionExt< T > : sealed::Sealed +where + T : Sized + Assign< T, T >, +{ + /// Sets the component on the `Option` if it is `None`. + /// + /// If the `Option` is `Some`, the `assign` method is called to update the existing value. + /// + /// # Parameters + /// + /// - `src`: The value to assign to the `Option`. + fn option_assign( & mut self, src : T ); +} + +#[ cfg( any( feature = "types_component_assign" ) ) ] +impl< T > OptionExt< T > for Option< T > +where + T : Sized + Assign< T, T >, +{ + #[ inline( always ) ] + fn option_assign( & mut self, src : T ) + { + match self + { + Some( self_ref ) => Assign::assign( self_ref, Into::< T >::into( src ) ), + None => * self = Some( src ), + } + } +} + +#[ cfg( any( feature = "types_component_assign" ) ) ] +mod sealed +{ + pub trait Sealed {} + impl< T > Sealed for Option< T > + where + T : Sized + super::Assign< T, T >, + {} +} + +/// The `AssignWithType` trait provides a mechanism to set a component on an object, +/// utilizing the type information explicitly. This trait extends the functionality of `Assign` +/// by allowing implementers to specify the component's type at the method call site, +/// enhancing expressiveness in code that manipulates object states. /// -/// This method allows an implementer of `SetWithTyp`e to set a component on self where the component's type is T, and the input value is of type `IntoT`, which can be converted into `T`. This method bridges the gap between dynamic type usage and static type enforcement, providing a flexible yet type-safe interface for modifying object states. +/// # Type Parameters /// -/// ### Type Parameters +/// - `T`: The type of the component to be set on the implementing object. This specifies +/// the exact type expected by the object as its component. +/// - `IntoT`: A type that can be converted into `T`, providing flexibility in the types of values +/// that can be used to set the component. /// -/// - `T` : The type of the component to be set on the implementing object. This specifies the exact type expected by the object as its component. -/// - `IntoT` : A type that can be converted into T, providing flexibility in the types of values that can be used to set the component. +/// # Examples /// -/// ### Example +/// Implementing `AssignWithType` to set a username on a struct: /// /// ```rust -/// use former_types::{ ComponentAssign, AssignWithType }; // use crate `former` instead of crate `former_types` unless you need to use crate `former_types` directly +/// use former_types::{ Assign, AssignWithType }; // use crate `former` instead of crate `former_types` unless you need to use crate `former_types` directly /// /// struct UserProfile /// { /// username : String, /// } /// -/// impl< IntoT : Into< String > > ComponentAssign< String, IntoT > for UserProfile -// where String: From< String >, +/// impl< IntoT : Into< String > > Assign< String, IntoT > for UserProfile /// { /// fn assign( &mut self, component : IntoT ) /// { @@ -84,33 +156,43 @@ where /// } /// /// let mut user_profile = UserProfile { username : String::new() }; -/// user_profile.assign_with_type::< String, _ >( "john_doe" ); +/// user_profile.assign_with_type::< String, _ >("john_doe"); /// /// assert_eq!( user_profile.username, "john_doe" ); /// ``` -/// - #[ cfg( any( feature = "types_component_assign" ) ) ] pub trait AssignWithType { - /// Function to set value of a component by its type. - fn assign_with_type< T, IntoT >( &mut self, component : IntoT ) + /// Sets the value of a component by its type. + /// + /// This method allows an implementer of `AssignWithType` to set a component on `self` + /// where the component's type is `T`, and the input value is of type `IntoT`, which can be + /// converted into `T`. This method bridges the gap between dynamic type usage and static type + /// enforcement, providing a flexible yet type-safe interface for modifying object states. + /// + /// # Parameters + /// + /// - `component`: The value to assign to the component. + /// + /// # Type Parameters + /// + /// - `T`: The type of the component to be set on the implementing object. + /// - `IntoT`: A type that can be converted into `T`. + fn assign_with_type< T, IntoT >( & mut self, component : IntoT ) where IntoT : Into< T >, - Self : ComponentAssign< T, IntoT >; + Self : Assign< T, IntoT >; } #[ cfg( any( feature = "types_component_assign" ) ) ] impl< S > AssignWithType for S { - #[ inline( always ) ] - fn assign_with_type< T, IntoT >( &mut self, component : IntoT ) + fn assign_with_type< T, IntoT >( & mut self, component : IntoT ) where IntoT : Into< T >, - Self : ComponentAssign< T, IntoT >, + Self : Assign< T, IntoT >, { - ComponentAssign::< T, IntoT >::assign( self, component ); + Assign::< T, IntoT >::assign( self, component ); } - } diff --git a/module/core/former_types/src/lib.rs b/module/core/former_types/src/lib.rs index 90b2af5410..51cfc78eab 100644 --- a/module/core/former_types/src/lib.rs +++ b/module/core/former_types/src/lib.rs @@ -8,7 +8,7 @@ #[ cfg( feature = "enabled" ) ] #[ cfg( feature = "derive_former" ) ] mod axiomatic; -/// Forming process. +/// Definition of former. #[ cfg( feature = "enabled" ) ] #[ cfg( feature = "derive_former" ) ] mod definition; diff --git a/module/core/macro_tools/Cargo.toml b/module/core/macro_tools/Cargo.toml index 75b5cd11fd..d6d8ce9d7b 100644 --- a/module/core/macro_tools/Cargo.toml +++ b/module/core/macro_tools/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "macro_tools" -version = "0.26.0" +version = "0.27.0" edition = "2021" authors = [ "Kostiantyn Wandalen ", @@ -28,7 +28,7 @@ all-features = false [features] default = [ "enabled" ] full = [ "enabled" ] -enabled = [] +enabled = [ "former_types/enabled", "interval_adapter/enabled" ] # qqq : put all files under features: macro_attr, macro_container_kind, ... @@ -39,9 +39,12 @@ proc-macro2 = { version = "~1.0.78", features = [] } quote = { version = "~1.0.35", features = [] } syn = { version = "~2.0.52", features = [ "full", "extra-traits" ] } +# qqq : optimize features list + ## internal -interval_adapter = { workspace = true, features = [ "default" ] } -# strs_tools = { workspace = true, features = [ "default" ] } +interval_adapter = { workspace = true, features = [] } +former_types = { workspace = true, features = [ "types_component_assign" ] } [dev-dependencies] test_tools = { workspace = true } +const_format = { version = "0.2.32" } diff --git a/module/core/macro_tools/Readme.md b/module/core/macro_tools/Readme.md index cf396b008f..62e2e0013a 100644 --- a/module/core/macro_tools/Readme.md +++ b/module/core/macro_tools/Readme.md @@ -7,27 +7,343 @@ Tools for writing procedural macros. -### Basic use-case +### Example: Trivial One +The purpose of `typ::type_parameters` is to extract type parameters from a given Rust type. +In this example, we generate a type `core::option::Option` and extract its type parameters. + ```rust +#[ cfg( not( feature = "enabled" ) ) ] +fn main(){} #[ cfg( feature = "enabled" ) ] +fn main() { - use macro_tools::exposed::*; + // Import necessary macros and modules from the `macro_tools` crate. + use macro_tools::{ typ, qt }; + // Generate a token stream representing the type `core::option::Option`. let code = qt!( core::option::Option< i8, i16, i32, i64 > ); + + // Parse the generated token stream into a `syn::Type` object. + // `syn::Type` is a syntax tree node representing a Rust type. let tree_type = syn::parse2::< syn::Type >( code ).unwrap(); + + // Extract type parameters from the parsed type. + // `typ::type_parameters` takes a reference to a `syn::Type` and a range. + // It returns a vector of type parameters within the specified range. + // Here, `0..=2` specifies that we are interested in the first three type parameters. let got = typ::type_parameters( &tree_type, 0..=2 ); + + // Iterate over the extracted type parameters and print each one. + // The `qt!` macro is used to convert the type parameter back to a token stream for printing. got.iter().for_each( | e | println!( "{}", qt!( #e ) ) ); - /* print : - i8 - i16 - i32 + + /* Expected output: + i8 + i16 + i32 */ } ``` +Try out `cargo run --example macro_tools_trivial`. +
+[See code](./examples/macro_tools_trivial.rs). + +### Example: Attribute Properties + +This example demonstrates an approach to parsing attributes and their properties. +The attributes are collected into a struct that aggregates them, and attribute properties +are parsed using reusable components from a library. The example shows how to use +`AttributePropertyBoolean` for parsing boolean properties and the roles of the traits +`AttributePropertyComponent` and `AttributeComponent`. The `Assign` trait is +also used to simplify the logic of assigning fields. + +Attributes are collected into a `ItemAttributes` struct, and attribute properties are parsed +using reusable components like `AttributePropertyBoolean`. + +- `AttributeComponent`: A trait that defines how an attribute should be parsed from a `syn::Attribute`. +- `AttributePropertyComponent`: A trait that defines a marker for attribute properties. +- `Assign`: A trait that simplifies the logic of assigning fields to a struct. Using a +component-based approach requires each field to have a unique type, which aligns with the +strengths of strongly-typed languages. This method ensures that the logic of +assigning values to fields is encapsulated within the fields themselves, promoting modularity +and reusability. + +The reusable property components from the library come with parameters that distinguish +different properties of the same type. This is useful when an attribute has multiple boolean +properties, for instance. Such an approach helps to avoid limitations where it is +always possible to define traits for custom types, while it may not be possible for types +defined in other crates. + +```rust + +#[ cfg( not( all( feature = "enabled", debug_assertions ) ) ) ] +fn main(){} +#[ cfg( all( feature = "enabled", debug_assertions ) ) ] +fn main() +{ + + use macro_tools:: + { + attr, + syn_err, + return_syn_err, + qt, + Result, + AttributeComponent, + AttributePropertyComponent, + AttributePropertyBoolean, + AttributePropertySingletone, + }; + use former_types::Assign; + + /// Represents the attributes of a struct. Aggregates all its attributes. + #[ derive( Debug, Default ) ] + pub struct ItemAttributes + { + /// Attribute for customizing the mutation process. + pub mutator : AttributeMutator, + } + + impl ItemAttributes + { + /// Constructs a `ItemAttributes` instance from an iterator of attributes. + /// + /// This function parses the provided attributes and assigns them to the + /// appropriate fields in the `ItemAttributes` struct. + pub fn from_attrs< 'a >( attrs : impl Iterator< Item = & 'a syn::Attribute > ) -> Result< Self > + { + let mut result = Self::default(); + + // Closure to generate an error message for unknown attributes. + let error = | attr : & syn::Attribute | -> syn::Error + { + let known_attributes = const_format::concatcp! + ( + "Known attributes are: ", + "debug", + ", ", AttributeMutator::KEYWORD, + "." + ); + syn_err! + ( + attr, + "Expects an attribute of format '#[ attribute( key1 = val1, key2 = val2 ) ]'\n {known_attributes}\n But got: '{}'", + qt! { #attr } + ) + }; + + for attr in attrs + { + let key_ident = attr.path().get_ident().ok_or_else( || error( attr ) )?; + let key_str = format!( "{}", key_ident ); + match key_str.as_ref() + { + AttributeMutator::KEYWORD => result.assign( AttributeMutator::from_meta( attr )? ), + "debug" => {}, + _ => {}, + } + } + + Ok( result ) + } + } + + /// Represents attributes for customizing the mutation process in a forming operation. + /// + /// ## Example of code + /// + /// ```ignore + /// #[ mutator( custom = true, debug = true ) ] + /// ``` + #[ derive( Debug, Default ) ] + pub struct AttributeMutator + { + /// Indicates whether a custom mutator should be generated. + /// Defaults to `false`, meaning no custom mutator is generated unless explicitly requested. + pub custom : AttributePropertyCustom, + /// Specifies whether to print code generated for the field. + /// Defaults to `false`, which means no hint is provided unless explicitly requested. + pub debug : AttributePropertyDebug, + } + + impl AttributeComponent for AttributeMutator + { + const KEYWORD : & 'static str = "mutator"; + + /// Parses a `syn::Attribute` into an `AttributeMutator`. + fn from_meta( attr : & syn::Attribute ) -> Result< Self > + { + match attr.meta + { + syn::Meta::List( ref meta_list ) => + { + return syn::parse2::< AttributeMutator >( meta_list.tokens.clone() ); + }, + syn::Meta::Path( ref _path ) => + { + return Ok( Default::default() ) + }, + _ => return_syn_err! + ( + attr, + "Expects an attribute of format `#[ mutator( custom = true ) ]`. \nGot: {}", + qt! { #attr } + ), + } + } + } + + // Implement `Assign` trait to allow assigning `AttributeMutator` to `ItemAttributes`. + impl< IntoT > Assign< AttributeMutator, IntoT > for ItemAttributes + where + IntoT : Into< AttributeMutator >, + { + #[ inline( always ) ] + fn assign( & mut self, component : IntoT ) + { + self.mutator = component.into(); + } + } + + // Implement `Assign` trait to allow assigning `AttributePropertyDebug` to `AttributeMutator`. + impl< IntoT > Assign< AttributePropertyDebug, IntoT > for AttributeMutator + where + IntoT : Into< AttributePropertyDebug >, + { + #[ inline( always ) ] + fn assign( & mut self, component : IntoT ) + { + self.debug = component.into(); + } + } + + // Implement `Assign` trait to allow assigning `AttributePropertyCustom` to `AttributeMutator`. + impl< IntoT > Assign< AttributePropertyCustom, IntoT > for AttributeMutator + where + IntoT : Into< AttributePropertyCustom >, + { + #[ inline( always ) ] + fn assign( & mut self, component : IntoT ) + { + self.custom = component.into(); + } + } + + impl syn::parse::Parse for AttributeMutator + { + fn parse( input : syn::parse::ParseStream< '_ > ) -> syn::Result< Self > + { + let mut result = Self::default(); + + let error = | ident : & syn::Ident | -> syn::Error + { + let known = const_format::concatcp! + ( + "Known entries of attribute ", AttributeMutator::KEYWORD, " are: ", + AttributePropertyCustom::KEYWORD, + ", ", AttributePropertyDebug::KEYWORD, + "." + ); + syn_err! + ( + ident, + r#"Expects an attribute of format '#[ mutator( custom = false ) ]' + {known} + But got: '{}' + "#, + qt! { #ident } + ) + }; + + while !input.is_empty() + { + let lookahead = input.lookahead1(); + if lookahead.peek( syn::Ident ) + { + let ident : syn::Ident = input.parse()?; + + match ident.to_string().as_str() + { + AttributePropertyCustom::KEYWORD => result.assign( AttributePropertyCustom::parse( input )? ), + AttributePropertyDebug::KEYWORD => result.assign( AttributePropertyDebug::from( true ) ), + _ => return Err( error( & ident ) ), + } + } + else + { + return Err( lookahead.error() ); + } + + // Optional comma handling + if input.peek( syn::Token![,] ) + { + input.parse::< syn::Token![,] >()?; + } + } + + Ok( result ) + } + } + + // == Attribute properties + + /// Marker type for attribute property to specify whether to provide a sketch as a hint. + /// Defaults to `false`, which means no hint is provided unless explicitly requested. + #[ derive( Debug, Default, Clone, Copy ) ] + pub struct AttributePropertyDebugMarker; + + impl AttributePropertyComponent for AttributePropertyDebugMarker + { + const KEYWORD : & 'static str = "debug"; + } + + /// Specifies whether to provide a sketch as a hint. + /// Defaults to `false`, which means no hint is provided unless explicitly requested. + pub type AttributePropertyDebug = AttributePropertySingletone< AttributePropertyDebugMarker >; + + // == + + /// Marker type for attribute property to indicate whether a custom code should be generated. + /// Defaults to `false`, meaning no custom code is generated unless explicitly requested. + #[ derive( Debug, Default, Clone, Copy ) ] + pub struct AttributePropertyCustomMarker; + + impl AttributePropertyComponent for AttributePropertyCustomMarker + { + const KEYWORD : & 'static str = "custom"; + } + + /// Indicates whether a custom code should be generated. + /// Defaults to `false`, meaning no custom code is generated unless explicitly requested. + pub type AttributePropertyCustom = AttributePropertyBoolean< AttributePropertyCustomMarker >; + + // == test code + + // Parse an attribute and construct a `ItemAttributes` instance. + let input : syn::Attribute = syn::parse_quote!( #[ mutator( custom = true ) ] ); + let attrs : ItemAttributes = ItemAttributes::from_attrs( std::iter::once( & input ) ).unwrap(); + println!( "{:?}", attrs ); + + // Test `AttributePropertyBoolean` functionality. + let attr : AttributePropertyBoolean< AttributePropertyDebugMarker > = AttributePropertyBoolean::default(); + assert_eq!( attr.internal(), false ); + let attr : AttributePropertyBoolean< AttributePropertyDebugMarker > = true.into(); + assert_eq!( attr.internal(), true ); + let attr : AttributePropertyBoolean< AttributePropertyDebugMarker > = false.into(); + assert_eq!( attr.internal(), false ); + +} + +``` + +Try out `cargo run --example macro_tools_attr_prop`. +
+[See code](./examples/macro_tools_attr_prop.rs). + ### To add to your project ```sh @@ -42,4 +358,3 @@ cd wTools cd examples/macro_tools_trivial cargo run ``` - diff --git a/module/core/macro_tools/examples/macro_tools_attr_prop.rs b/module/core/macro_tools/examples/macro_tools_attr_prop.rs new file mode 100644 index 0000000000..4625e15154 --- /dev/null +++ b/module/core/macro_tools/examples/macro_tools_attr_prop.rs @@ -0,0 +1,290 @@ +//! +//! ### Example: Attribute Properties +//! +//! This example demonstrates an approach to parsing attributes and their properties. +//! The attributes are collected into a struct that aggregates them, and attribute properties +//! are parsed using reusable components from a library. The example shows how to use +//! `AttributePropertyBoolean` for parsing boolean properties and the roles of the traits +//! `AttributePropertyComponent` and `AttributeComponent`. The `Assign` trait is +//! also used to simplify the logic of assigning fields. +//! +//! Attributes are collected into a `ItemAttributes` struct, and attribute properties are parsed +//! using reusable components like `AttributePropertyBoolean`. +//! +//! - `AttributeComponent`: A trait that defines how an attribute should be parsed from a `syn::Attribute`. +//! - `AttributePropertyComponent`: A trait that defines a marker for attribute properties. +//! - `Assign`: A trait that simplifies the logic of assigning fields to a struct. Using a +//! component-based approach requires each field to have a unique type, which aligns with the +//! strengths of strongly-typed languages. This method ensures that the logic of +//! assigning values to fields is encapsulated within the fields themselves, promoting modularity +//! and reusability. +//! +//! The reusable property components from the library come with parameters that distinguish +//! different properties of the same type. This is useful when an attribute has multiple boolean +//! properties, for instance. Such an approach helps to avoid limitations where it is +//! always possible to define traits for custom types, while it may not be possible for types +//! defined in other crates. +//! + +#[ cfg( not( all( feature = "enabled", debug_assertions ) ) ) ] +fn main(){} +#[ cfg( all( feature = "enabled", debug_assertions ) ) ] +fn main() +{ + + use macro_tools:: + { + attr, + syn_err, + return_syn_err, + qt, + Result, + AttributeComponent, + AttributePropertyComponent, + AttributePropertyBoolean, + AttributePropertySingletone, + }; + use former_types::Assign; + + /// Represents the attributes of a struct. Aggregates all its attributes. + #[ derive( Debug, Default ) ] + pub struct ItemAttributes + { + /// Attribute for customizing the mutation process. + pub mutator : AttributeMutator, + } + + impl ItemAttributes + { + /// Constructs a `ItemAttributes` instance from an iterator of attributes. + /// + /// This function parses the provided attributes and assigns them to the + /// appropriate fields in the `ItemAttributes` struct. + pub fn from_attrs< 'a >( attrs : impl Iterator< Item = & 'a syn::Attribute > ) -> Result< Self > + { + let mut result = Self::default(); + + // Closure to generate an error message for unknown attributes. + let error = | attr : & syn::Attribute | -> syn::Error + { + let known_attributes = const_format::concatcp! + ( + "Known attributes are: ", + "debug", + ", ", AttributeMutator::KEYWORD, + "." + ); + syn_err! + ( + attr, + "Expects an attribute of format '#[ attribute( key1 = val1, key2 = val2 ) ]'\n {known_attributes}\n But got: '{}'", + qt! { #attr } + ) + }; + + for attr in attrs + { + let key_ident = attr.path().get_ident().ok_or_else( || error( attr ) )?; + let key_str = format!( "{}", key_ident ); + // if attr::is_standard( & key_str ) + // { + // continue; + // } + match key_str.as_ref() + { + AttributeMutator::KEYWORD => result.assign( AttributeMutator::from_meta( attr )? ), + "debug" => {}, + _ => {}, + // _ => return Err( error( attr ) ), + } + } + + Ok( result ) + } + } + + /// Represents attributes for customizing the mutation process in a forming operation. + /// + /// ## Example of code + /// + /// ```ignore + /// #[ mutator( custom = true, debug = true ) ] + /// ``` + #[ derive( Debug, Default ) ] + pub struct AttributeMutator + { + /// Indicates whether a custom mutator should be generated. + /// Defaults to `false`, meaning no custom mutator is generated unless explicitly requested. + pub custom : AttributePropertyCustom, + /// Specifies whether to print code generated for the field. + /// Defaults to `false`, which means no hint is provided unless explicitly requested. + pub debug : AttributePropertyDebug, + } + + impl AttributeComponent for AttributeMutator + { + const KEYWORD : & 'static str = "mutator"; + + /// Parses a `syn::Attribute` into an `AttributeMutator`. + fn from_meta( attr : & syn::Attribute ) -> Result< Self > + { + match attr.meta + { + syn::Meta::List( ref meta_list ) => + { + return syn::parse2::< AttributeMutator >( meta_list.tokens.clone() ); + }, + syn::Meta::Path( ref _path ) => + { + return Ok( Default::default() ) + }, + _ => return_syn_err! + ( + attr, + "Expects an attribute of format `#[ mutator( custom = true ) ]`. \nGot: {}", + qt! { #attr } + ), + } + } + } + + // Implement `Assign` trait to allow assigning `AttributeMutator` to `ItemAttributes`. + impl< IntoT > Assign< AttributeMutator, IntoT > for ItemAttributes + where + IntoT : Into< AttributeMutator >, + { + #[ inline( always ) ] + fn assign( & mut self, component : IntoT ) + { + self.mutator = component.into(); + } + } + + // Implement `Assign` trait to allow assigning `AttributePropertyDebug` to `AttributeMutator`. + impl< IntoT > Assign< AttributePropertyDebug, IntoT > for AttributeMutator + where + IntoT : Into< AttributePropertyDebug >, + { + #[ inline( always ) ] + fn assign( & mut self, component : IntoT ) + { + self.debug = component.into(); + } + } + + // Implement `Assign` trait to allow assigning `AttributePropertyCustom` to `AttributeMutator`. + impl< IntoT > Assign< AttributePropertyCustom, IntoT > for AttributeMutator + where + IntoT : Into< AttributePropertyCustom >, + { + #[ inline( always ) ] + fn assign( & mut self, component : IntoT ) + { + self.custom = component.into(); + } + } + + impl syn::parse::Parse for AttributeMutator + { + fn parse( input : syn::parse::ParseStream< '_ > ) -> syn::Result< Self > + { + let mut result = Self::default(); + + let error = | ident : & syn::Ident | -> syn::Error + { + let known = const_format::concatcp! + ( + "Known entries of attribute ", AttributeMutator::KEYWORD, " are: ", + AttributePropertyCustom::KEYWORD, + ", ", AttributePropertyDebug::KEYWORD, + "." + ); + syn_err! + ( + ident, + r#"Expects an attribute of format '#[ mutator( custom = false ) ]' + {known} + But got: '{}' + "#, + qt! { #ident } + ) + }; + + while !input.is_empty() + { + let lookahead = input.lookahead1(); + if lookahead.peek( syn::Ident ) + { + let ident : syn::Ident = input.parse()?; + + match ident.to_string().as_str() + { + AttributePropertyCustom::KEYWORD => result.assign( AttributePropertyCustom::parse( input )? ), + AttributePropertyDebug::KEYWORD => result.assign( AttributePropertyDebug::from( true ) ), + _ => return Err( error( & ident ) ), + } + } + else + { + return Err( lookahead.error() ); + } + + // Optional comma handling + if input.peek( syn::Token![,] ) + { + input.parse::< syn::Token![,] >()?; + } + } + + Ok( result ) + } + } + + // == Attribute properties + + /// Marker type for attribute property to specify whether to provide a sketch as a hint. + /// Defaults to `false`, which means no hint is provided unless explicitly requested. + #[ derive( Debug, Default, Clone, Copy ) ] + pub struct AttributePropertyDebugMarker; + + impl AttributePropertyComponent for AttributePropertyDebugMarker + { + const KEYWORD : & 'static str = "debug"; + } + + /// Specifies whether to provide a sketch as a hint. + /// Defaults to `false`, which means no hint is provided unless explicitly requested. + pub type AttributePropertyDebug = AttributePropertySingletone< AttributePropertyDebugMarker >; + + // == + + /// Marker type for attribute property to indicate whether a custom code should be generated. + /// Defaults to `false`, meaning no custom code is generated unless explicitly requested. + #[ derive( Debug, Default, Clone, Copy ) ] + pub struct AttributePropertyCustomMarker; + + impl AttributePropertyComponent for AttributePropertyCustomMarker + { + const KEYWORD : & 'static str = "custom"; + } + + /// Indicates whether a custom code should be generated. + /// Defaults to `false`, meaning no custom code is generated unless explicitly requested. + pub type AttributePropertyCustom = AttributePropertyBoolean< AttributePropertyCustomMarker >; + + // == test code + + // Parse an attribute and construct a `ItemAttributes` instance. + let input : syn::Attribute = syn::parse_quote!( #[ mutator( custom = true ) ] ); + let attrs : ItemAttributes = ItemAttributes::from_attrs( std::iter::once( & input ) ).unwrap(); + println!( "{:?}", attrs ); + + // Test `AttributePropertyBoolean` functionality. + let attr : AttributePropertyBoolean< AttributePropertyDebugMarker > = AttributePropertyBoolean::default(); + assert_eq!( attr.internal(), false ); + let attr : AttributePropertyBoolean< AttributePropertyDebugMarker > = true.into(); + assert_eq!( attr.internal(), true ); + let attr : AttributePropertyBoolean< AttributePropertyDebugMarker > = false.into(); + assert_eq!( attr.internal(), false ); + +} diff --git a/module/core/macro_tools/examples/macro_tools_trivial.rs b/module/core/macro_tools/examples/macro_tools_trivial.rs index 73cd1af6c8..e92559b193 100644 --- a/module/core/macro_tools/examples/macro_tools_trivial.rs +++ b/module/core/macro_tools/examples/macro_tools_trivial.rs @@ -1,19 +1,39 @@ -//! qqq : write proper description +//! This example demonstrates the use of `typ::type_parameters` from the `macro_tools` crate. +//! +//! ### Example: Trivial One +//! +//! The purpose of `typ::type_parameters` is to extract type parameters from a given Rust type. +//! In this example, we generate a type `core::option::Option` and extract its type parameters. +//! + #[ cfg( not( feature = "enabled" ) ) ] fn main(){} - #[ cfg( feature = "enabled" ) ] fn main() { + // Import necessary macros and modules from the `macro_tools` crate. use macro_tools::{ typ, qt }; + // Generate a token stream representing the type `core::option::Option`. let code = qt!( core::option::Option< i8, i16, i32, i64 > ); + + // Parse the generated token stream into a `syn::Type` object. + // `syn::Type` is a syntax tree node representing a Rust type. let tree_type = syn::parse2::< syn::Type >( code ).unwrap(); + + // Extract type parameters from the parsed type. + // `typ::type_parameters` takes a reference to a `syn::Type` and a range. + // It returns a vector of type parameters within the specified range. + // Here, `0..=2` specifies that we are interested in the first three type parameters. let got = typ::type_parameters( &tree_type, 0..=2 ); + + // Iterate over the extracted type parameters and print each one. + // The `qt!` macro is used to convert the type parameter back to a token stream for printing. got.iter().for_each( | e | println!( "{}", qt!( #e ) ) ); - /* print : - i8 - i16 - i32 + + /* Expected output: + i8 + i16 + i32 */ -} \ No newline at end of file +} diff --git a/module/core/macro_tools/src/attr.rs b/module/core/macro_tools/src/attr.rs index a0bb4fbd30..4524ded53e 100644 --- a/module/core/macro_tools/src/attr.rs +++ b/module/core/macro_tools/src/attr.rs @@ -321,17 +321,22 @@ pub( crate ) mod private } } - /// Trait for components of strcuture aggregating attributes that can be constructed from a meta attribute. + /// Trait for components of a structure aggregating attributes that can be constructed from a meta attribute. /// /// The `AttributeComponent` trait defines the interface for components that can be created /// from a `syn::Attribute` meta item. Implementors of this trait are required to define /// a constant `KEYWORD` that identifies the type of the component and a method `from_meta` /// that handles the construction of the component from the given attribute. /// + /// This trait is designed to facilitate modular and reusable parsing of attributes applied + /// to structs, enums, or other constructs. By implementing this trait, you can create specific + /// components from attributes and then aggregate these components into a larger structure. + /// /// # Example /// /// ```rust /// use macro_tools::{ AttributeComponent, Result }; + /// use syn::{ Attribute, Error }; /// /// struct MyComponent; /// @@ -339,14 +344,24 @@ pub( crate ) mod private /// { /// const KEYWORD : &'static str = "my_component"; /// - /// fn from_meta( attr : &syn::Attribute ) -> Result< Self > + /// fn from_meta( attr : &Attribute ) -> Result /// { /// // Parsing logic here + /// // Return Ok(MyComponent) if parsing is successful + /// // Return Err(Error::new_spanned(attr, "error message")) if parsing fails /// Ok( MyComponent ) /// } /// } /// ``` - /// xxx : improve documentation + /// + /// # Parameters + /// + /// - `attr` : A reference to the `syn::Attribute` from which the component is to be constructed. + /// + /// # Returns + /// + /// A `Result` containing the constructed component if successful, or an error if the parsing fails. + /// pub trait AttributeComponent where Self : Sized, @@ -373,14 +388,36 @@ pub( crate ) mod private fn from_meta( attr : &syn::Attribute ) -> Result< Self >; } - /// xxx : write documentation + /// Trait for properties of an attribute component that can be identified by a keyword. + /// + /// The `AttributePropertyComponent` trait defines the interface for attribute properties + /// that can be identified by a specific keyword. Implementors of this trait are required + /// to define a constant `KEYWORD` that identifies the type of the property. + /// + /// This trait is useful in scenarios where attributes may have multiple properties + /// that need to be parsed and handled separately. By defining a unique keyword for each property, + /// the parsing logic can accurately identify and process each property. + /// + /// # Example + /// + /// ```rust + /// use macro_tools::AttributePropertyComponent; + /// + /// struct MyProperty; + /// + /// impl AttributePropertyComponent for MyProperty + /// { + /// const KEYWORD : &'static str = "my_property"; + /// } + /// ``` + /// pub trait AttributePropertyComponent where Self : Sized, { /// The keyword that identifies the component. /// - /// This constant is used to match the attribute to the corresponding component. + /// This constant is used to match the attribute to the corresponding property. /// Each implementor of this trait must provide a unique keyword for its type. const KEYWORD : &'static str; } diff --git a/module/core/macro_tools/src/attr_prop.rs b/module/core/macro_tools/src/attr_prop.rs index 0193a8653a..4e5020eff2 100644 --- a/module/core/macro_tools/src/attr_prop.rs +++ b/module/core/macro_tools/src/attr_prop.rs @@ -1,7 +1,6 @@ //! //! Attribute's properties. Reuse them to define how to parse properties of an attribute. //! -//! //! # Example //! //! ```rust @@ -48,7 +47,6 @@ //! if lookahead.peek( syn::Ident ) //! { //! let ident : syn::Ident = input.parse()?; -//! input.parse::< syn::Token![=] >()?; //! match ident.to_string().as_str() //! { //! DebugMarker::KEYWORD => debug = input.parse()?, @@ -72,7 +70,7 @@ //! } //! } //! -//! let input : syn::Attribute = syn::parse_quote!( #[ attribute( enabled = true, debug = false ) ] ); +//! let input : syn::Attribute = syn::parse_quote!( #[ attribute( enabled = true ) ] ); //! let meta = match input.meta //! { //! syn::Meta::List( meta_list ) => meta_list, @@ -97,480 +95,17 @@ //! The `parse_quote!` macro is used to create a `syn::Attribute` instance with the attribute syntax, //! which is then parsed into the `MyAttributes` struct. The resulting `MyAttributes` instance is printed to the console. -// xxx : qqq : improve documentation, add examples +mod singletone; +mod singletone_optional; +mod boolean; +mod boolean_optional; +mod syn; +mod syn_optional; /// Internal namespace. pub( crate ) mod private { - use crate::*; - - // = AttributePropertyBoolean - - /// A generic boolean attribute property. - /// Defaults to `false`. - /// - /// # Example - /// - /// ```rust - /// use macro_tools::AttributePropertyBoolean; - /// - /// #[ derive( Debug, Default, Clone, Copy ) ] - /// pub struct DebugMarker; - /// - /// #[ derive( Debug, Default, Clone, Copy ) ] - /// pub struct EnabledMarker; - /// - /// pub trait AttributePropertyComponent - /// { - /// const KEYWORD : &'static str; - /// } - /// - /// impl AttributePropertyComponent for DebugMarker - /// { - /// const KEYWORD : &'static str = "debug"; - /// } - /// - /// impl AttributePropertyComponent for EnabledMarker - /// { - /// const KEYWORD : &'static str = "enabled"; - /// } - /// - /// #[ derive( Debug, Default ) ] - /// struct MyAttributes - /// { - /// pub debug : AttributePropertyBoolean< DebugMarker >, - /// pub enabled : AttributePropertyBoolean< EnabledMarker >, - /// } - /// - /// impl syn::parse::Parse for MyAttributes - /// { - /// fn parse( input : syn::parse::ParseStream< '_ > ) -> syn::Result< Self > - /// { - /// let mut debug = AttributePropertyBoolean::< DebugMarker >::default(); - /// let mut enabled = AttributePropertyBoolean::< EnabledMarker >::default(); - /// - /// while !input.is_empty() - /// { - /// let lookahead = input.lookahead1(); - /// if lookahead.peek( syn::Ident ) - /// { - /// let ident : syn::Ident = input.parse()?; - /// input.parse::< syn::Token![=] >()?; - /// match ident.to_string().as_str() - /// { - /// DebugMarker::KEYWORD => debug = input.parse()?, - /// EnabledMarker::KEYWORD => enabled = input.parse()?, - /// _ => return Err( lookahead.error() ), - /// } - /// } - /// else - /// { - /// return Err( lookahead.error() ); - /// } - /// - /// // Optional comma handling - /// if input.peek( syn::Token![,] ) - /// { - /// input.parse::< syn::Token![,] >()?; - /// } - /// } - /// - /// Ok( MyAttributes { debug, enabled } ) - /// } - /// } - /// - /// let input : syn::Attribute = syn::parse_quote!( #[ attribute( enabled = true, debug = false ) ] ); - /// let meta = match input.meta - /// { - /// syn::Meta::List( meta_list ) => meta_list, - /// _ => panic!( "Expected a Meta::List" ), - /// }; - /// - /// let nested_meta_stream : proc_macro2::TokenStream = meta.tokens; - /// let attrs : MyAttributes = syn::parse2( nested_meta_stream ).unwrap(); - /// println!( "{:?}", attrs ); - /// ``` - /// - /// In this example, the `AttributePropertyBoolean` struct is used to define attributes with boolean properties. - /// The `DebugMarker` and `EnabledMarker` structs act as markers to distinguish between different boolean attributes. - /// The `MyAttributes` struct aggregates these boolean attributes. - /// - /// The `Parse` implementation for `MyAttributes` iterates through the attribute's key-value pairs, - /// identifying each by its marker's keyword and parsing the boolean value. - /// It uses the `ParseStream` to parse identifiers and their associated values, - /// matching them to the appropriate marker's keyword. - /// If an unrecognized identifier is encountered, it returns an error. - /// - /// The `parse_quote!` macro is used to create a `syn::Attribute` instance with the attribute syntax, - /// which is then parsed into the `MyAttributes` struct. The resulting `MyAttributes` instance is printed to the console. - - #[ derive( Debug, Default, Clone, Copy ) ] - pub struct AttributePropertyBoolean< Marker >( bool, ::core::marker::PhantomData< Marker > ); - - impl< Marker > AttributePropertyBoolean< Marker > - { - /// Just unwraps and returns the internal data. - pub fn internal( self ) -> bool - { - self.0 - } - - /// Returns a reference to the internal boolean value. - pub fn ref_internal( &self ) -> &bool - { - &self.0 - } - } - - impl< Marker > AttributePropertyComponent for AttributePropertyBoolean< Marker > - where - Marker : AttributePropertyComponent, - { - const KEYWORD : &'static str = Marker::KEYWORD; - } - - impl< Marker > syn::parse::Parse for AttributePropertyBoolean< Marker > - { - fn parse( input : syn::parse::ParseStream< '_ > ) -> syn::Result< Self > - { - let value : syn::LitBool = input.parse()?; - Ok( value.value.into() ) - } - } - - impl< Marker > From< bool > for AttributePropertyBoolean< Marker > - { - #[ inline( always ) ] - fn from( src : bool ) -> Self - { - Self( src, Default::default() ) - } - } - - impl< Marker > From< AttributePropertyBoolean< Marker > > for bool - { - #[ inline( always ) ] - fn from( src : AttributePropertyBoolean< Marker > ) -> Self - { - src.0 - } - } - - impl< Marker > core::ops::Deref for AttributePropertyBoolean< Marker > - { - type Target = bool; - - #[ inline( always ) ] - fn deref( &self ) -> &bool - { - &self.0 - } - } - - impl< Marker > AsRef< bool > for AttributePropertyBoolean< Marker > - { - #[ inline( always ) ] - fn as_ref( &self ) -> &bool - { - &self.0 - } - } - - // = AttributePropertyOptionalBoolean - - /// A generic optional boolean attribute property: `Option< bool >`. - /// Defaults to `false`. - #[ derive( Debug, Default, Clone, Copy ) ] - pub struct AttributePropertyOptionalBoolean< Marker >( Option< bool >, ::core::marker::PhantomData< Marker > ); - - impl< Marker > AttributePropertyOptionalBoolean< Marker > - { - /// Just unwraps and returns the internal data. - pub fn internal( self ) -> Option< bool > - { - self.0 - } - - /// Returns a reference to the internal optional boolean value. - pub fn ref_internal( &self ) -> Option< &bool > - { - self.0.as_ref() - } - } - - impl< Marker > AttributePropertyComponent for AttributePropertyOptionalBoolean< Marker > - where - Marker : AttributePropertyComponent, - { - const KEYWORD : &'static str = Marker::KEYWORD; - } - - impl< Marker > syn::parse::Parse for AttributePropertyOptionalBoolean< Marker > - { - fn parse( input : syn::parse::ParseStream< '_ > ) -> syn::Result< Self > - { - let value : syn::LitBool = input.parse()?; - Ok( value.value.into() ) - } - } - - impl< Marker > From< bool > for AttributePropertyOptionalBoolean< Marker > - { - #[ inline( always ) ] - fn from( src : bool ) -> Self - { - Self( Some( src ), Default::default() ) - } - } - - impl< Marker > From< Option< bool > > for AttributePropertyOptionalBoolean< Marker > - { - #[ inline( always ) ] - fn from( src : Option< bool > ) -> Self - { - Self( src, Default::default() ) - } - } - - impl< Marker > From< AttributePropertyOptionalBoolean< Marker > > for Option< bool > - { - #[ inline( always ) ] - fn from( src : AttributePropertyOptionalBoolean< Marker > ) -> Self - { - src.0 - } - } - - impl< Marker > core::ops::Deref for AttributePropertyOptionalBoolean< Marker > - { - type Target = Option< bool >; - #[ inline( always ) ] - fn deref( &self ) -> &Option< bool > - { - &self.0 - } - } - - impl< Marker > AsRef< Option< bool > > for AttributePropertyOptionalBoolean< Marker > - { - #[ inline( always ) ] - fn as_ref( &self ) -> &Option< bool > - { - &self.0 - } - } - - // = AttributePropertySyn - - /// Property of an attribute which simply wraps one of the standard `syn` types. - #[ derive( Debug, Clone ) ] - pub struct AttributePropertySyn< T, Marker >( T, ::core::marker::PhantomData< Marker > ) - where - T : syn::parse::Parse + quote::ToTokens; - - impl< T, Marker > AttributePropertySyn< T, Marker > - where - T : syn::parse::Parse + quote::ToTokens, - { - /// Just unwraps and returns the internal data. - #[ allow( dead_code ) ] - pub fn internal( self ) -> T - { - self.0 - } - - /// Returns a reference to the internal data. - #[ allow( dead_code ) ] - pub fn ref_internal( &self ) -> &T - { - &self.0 - } - } - - impl< T, Marker > AttributePropertyComponent for AttributePropertySyn< T, Marker > - where - T : syn::parse::Parse + quote::ToTokens, - Marker : AttributePropertyComponent, - { - const KEYWORD : &'static str = Marker::KEYWORD; - } - - impl< T, Marker > syn::parse::Parse for AttributePropertySyn< T, Marker > - where - T : syn::parse::Parse + quote::ToTokens, - { - fn parse( input : syn::parse::ParseStream< '_ > ) -> syn::Result< Self > - { - let value : T = input.parse()?; - Ok( value.into() ) - } - } - - impl< T, Marker > quote::ToTokens for AttributePropertySyn< T, Marker > - where - T : syn::parse::Parse + quote::ToTokens, - { - fn to_tokens( &self, tokens : &mut proc_macro2::TokenStream ) - { - self.0.to_tokens( tokens ); - } - } - - impl< T, Marker > core::ops::Deref for AttributePropertySyn< T, Marker > - where T : syn::parse::Parse + quote::ToTokens - { - type Target = T; - #[ inline( always ) ] - fn deref( &self ) -> &T - { - &self.0 - } - } - - impl< T, Marker > AsRef< T > for AttributePropertySyn< T, Marker > - where T : syn::parse::Parse + quote::ToTokens - { - #[ inline( always ) ] - fn as_ref( &self ) -> &T - { - &self.0 - } - } - - impl< T, Marker > From< T > for AttributePropertySyn< T, Marker > - where T : syn::parse::Parse + quote::ToTokens - { - #[ inline( always ) ] - fn from( src : T ) -> Self - { - Self( src, Default::default() ) - } - } - - // = AttributePropertyOptionalSyn - - /// Property of an attribute which simply wraps one of the standard `syn` types and keeps it optional. - #[ derive( Debug, Clone ) ] - pub struct AttributePropertyOptionalSyn< T, Marker >( Option< T >, ::core::marker::PhantomData< Marker > ) - where - T : syn::parse::Parse + quote::ToTokens; - - impl< T, Marker > AttributePropertyOptionalSyn< T, Marker > - where - T : syn::parse::Parse + quote::ToTokens, - { - /// Just unwraps and returns the internal data. - pub fn internal( self ) -> Option< T > - { - self.0 - } - - /// Returns an Option reference to the internal data. - pub fn ref_internal( &self ) -> Option< &T > - { - self.0.as_ref() - } - } - - impl< T, Marker > AttributePropertyComponent for AttributePropertyOptionalSyn< T, Marker > - where - T : syn::parse::Parse + quote::ToTokens, - Marker : AttributePropertyComponent, - { - const KEYWORD : &'static str = Marker::KEYWORD; - } - - impl< T, Marker > Default for AttributePropertyOptionalSyn< T, Marker > - where - T : syn::parse::Parse + quote::ToTokens, - { - fn default() -> Self - { - Self( None, Default::default() ) - } - } - - impl< T, Marker > syn::parse::Parse for AttributePropertyOptionalSyn< T, Marker > - where - T : syn::parse::Parse + quote::ToTokens, - { - fn parse( input : syn::parse::ParseStream< '_ > ) -> syn::Result< Self > - { - let value : T = input.parse()?; - Ok( value.into() ) - } - } - - impl< T, Marker > quote::ToTokens for AttributePropertyOptionalSyn< T, Marker > - where - T : syn::parse::Parse + quote::ToTokens, - { - fn to_tokens( &self, tokens : &mut proc_macro2::TokenStream ) - { - self.0.to_tokens( tokens ); - } - } - - impl< T, Marker > core::ops::Deref for AttributePropertyOptionalSyn< T, Marker > - where T : syn::parse::Parse + quote::ToTokens - { - type Target = Option< T >; - #[ inline( always ) ] - fn deref( &self ) -> &Option< T > - { - &self.0 - } - } - - impl< T, Marker > AsRef< Option< T > > for AttributePropertyOptionalSyn< T, Marker > - where T : syn::parse::Parse + quote::ToTokens - { - #[ inline( always ) ] - fn as_ref( &self ) -> &Option< T > - { - &self.0 - } - } - - impl< T, Marker > From< T > for AttributePropertyOptionalSyn< T, Marker > - where T : syn::parse::Parse + quote::ToTokens - { - #[ inline( always ) ] - fn from( src : T ) -> Self - { - Self( Some( src ), Default::default() ) - } - } - - impl< T, Marker > From< Option< T > > for AttributePropertyOptionalSyn< T, Marker > - where T : syn::parse::Parse + quote::ToTokens - { - #[ inline( always ) ] - fn from( src : Option< T > ) -> Self - { - Self( src, Default::default() ) - } - } - - impl< T, Marker > From< AttributePropertyOptionalSyn< T, Marker > > for Option< T > - where T : syn::parse::Parse + quote::ToTokens - { - #[ inline( always ) ] - fn from( src : AttributePropertyOptionalSyn< T, Marker > ) -> Self - { - src.0 - } - } - - impl< 'a, T, Marker > From< &'a AttributePropertyOptionalSyn< T, Marker > > for Option< &'a T > - where T : syn::parse::Parse + quote::ToTokens - { - #[ inline( always ) ] - fn from( src : &'a AttributePropertyOptionalSyn< T, Marker > ) -> Self - { - src.0.as_ref() - } - } + // use crate::*; } @@ -608,12 +143,22 @@ pub mod exposed pub use super::prelude::*; #[ doc( inline ) ] #[ allow( unused_imports ) ] - pub use super::private:: - { - AttributePropertyBoolean, - AttributePropertyOptionalBoolean, - AttributePropertySyn, - AttributePropertyOptionalSyn, + pub use super:: + { + + singletone::AttributePropertySingletone, + singletone::AttributePropertySingletoneMarker, + singletone_optional::AttributePropertyOptionalSingletone, + singletone_optional::AttributePropertyOptionalSingletoneMarker, + boolean::AttributePropertyBoolean, + boolean::AttributePropertyBooleanMarker, + boolean_optional::AttributePropertyOptionalBoolean, + boolean_optional::AttributePropertyOptionalBooleanMarker, + syn::AttributePropertySyn, + syn::AttributePropertySynMarker, + syn_optional::AttributePropertyOptionalSyn, + syn_optional::AttributePropertyOptionalSynMarker, + }; } diff --git a/module/core/macro_tools/src/attr_prop/boolean.rs b/module/core/macro_tools/src/attr_prop/boolean.rs new file mode 100644 index 0000000000..4472b3ae42 --- /dev/null +++ b/module/core/macro_tools/src/attr_prop/boolean.rs @@ -0,0 +1,196 @@ +//! +//! A generic boolean attribute property. +//! Defaults to `false`. +//! + +use crate::*; +use former_types::Assign; + +/// Default marker for `AttributePropertyBoolean`. +/// Used if no marker is defined as parameter. +#[ derive( Debug, Default, Clone, Copy ) ] +pub struct AttributePropertyBooleanMarker; + +/// A generic boolean attribute property. +/// Defaults to `false`. +/// +/// # Example +/// +/// ```rust +/// use macro_tools::AttributePropertyBoolean; +/// +/// #[ derive( Debug, Default, Clone, Copy ) ] +/// pub struct DebugMarker; +/// +/// #[ derive( Debug, Default, Clone, Copy ) ] +/// pub struct EnabledMarker; +/// +/// pub trait AttributePropertyComponent +/// { +/// const KEYWORD : &'static str; +/// } +/// +/// impl AttributePropertyComponent for DebugMarker +/// { +/// const KEYWORD : &'static str = "debug"; +/// } +/// +/// impl AttributePropertyComponent for EnabledMarker +/// { +/// const KEYWORD : &'static str = "enabled"; +/// } +/// +/// #[ derive( Debug, Default ) ] +/// struct MyAttributes +/// { +/// pub debug : AttributePropertyBoolean< DebugMarker >, +/// pub enabled : AttributePropertyBoolean< EnabledMarker >, +/// } +/// +/// impl syn::parse::Parse for MyAttributes +/// { +/// fn parse( input : syn::parse::ParseStream< '_ > ) -> syn::Result< Self > +/// { +/// let mut debug = AttributePropertyBoolean::< DebugMarker >::default(); +/// let mut enabled = AttributePropertyBoolean::< EnabledMarker >::default(); +/// +/// while !input.is_empty() +/// { +/// let lookahead = input.lookahead1(); +/// if lookahead.peek( syn::Ident ) +/// { +/// let ident : syn::Ident = input.parse()?; +/// match ident.to_string().as_str() +/// { +/// DebugMarker::KEYWORD => debug = input.parse()?, +/// EnabledMarker::KEYWORD => enabled = input.parse()?, +/// _ => return Err( lookahead.error() ), +/// } +/// } +/// else +/// { +/// return Err( lookahead.error() ); +/// } +/// +/// // Optional comma handling +/// if input.peek( syn::Token![,] ) +/// { +/// input.parse::< syn::Token![,] >()?; +/// } +/// } +/// +/// Ok( MyAttributes { debug, enabled } ) +/// } +/// } +/// +/// let input : syn::Attribute = syn::parse_quote!( #[ attribute( enabled = true ) ] ); +/// let meta = match input.meta +/// { +/// syn::Meta::List( meta_list ) => meta_list, +/// _ => panic!( "Expected a Meta::List" ), +/// }; +/// +/// let nested_meta_stream : proc_macro2::TokenStream = meta.tokens; +/// let attrs : MyAttributes = syn::parse2( nested_meta_stream ).unwrap(); +/// println!( "{:?}", attrs ); +/// ``` +/// +/// In this example, the `AttributePropertyBoolean` struct is used to define attributes with boolean properties. +/// The `DebugMarker` and `EnabledMarker` structs act as markers to distinguish between different boolean attributes. +/// The `MyAttributes` struct aggregates these boolean attributes. +/// +/// The `Parse` implementation for `MyAttributes` iterates through the attribute's key-value pairs, +/// identifying each by its marker's keyword and parsing the boolean value. +/// It uses the `ParseStream` to parse identifiers and their associated values, +/// matching them to the appropriate marker's keyword. +/// If an unrecognized identifier is encountered, it returns an error. +/// +/// The `parse_quote!` macro is used to create a `syn::Attribute` instance with the attribute syntax, +/// which is then parsed into the `MyAttributes` struct. The resulting `MyAttributes` instance is printed to the console. + +#[ derive( Debug, Default, Clone, Copy ) ] +pub struct AttributePropertyBoolean< Marker = AttributePropertyBooleanMarker >( bool, ::core::marker::PhantomData< Marker > ); + +impl< Marker > AttributePropertyBoolean< Marker > +{ + /// Just unwraps and returns the internal data. + #[ inline( always ) ] + pub fn internal( self ) -> bool + { + self.0 + } + + /// Returns a reference to the internal boolean value. + #[ inline( always ) ] + pub fn ref_internal( &self ) -> &bool + { + &self.0 + } +} + +impl< Marker, IntoT > Assign< AttributePropertyBoolean< Marker >, IntoT > +for AttributePropertyBoolean< Marker > +where + IntoT : Into< AttributePropertyBoolean< Marker > >, +{ + #[ inline( always ) ] + fn assign( &mut self, component : IntoT ) + { + *self = component.into(); + } +} + +impl< Marker > AttributePropertyComponent for AttributePropertyBoolean< Marker > +where + Marker : AttributePropertyComponent, +{ + const KEYWORD : &'static str = Marker::KEYWORD; +} + +impl< Marker > syn::parse::Parse for AttributePropertyBoolean< Marker > +{ + fn parse( input : syn::parse::ParseStream< '_ > ) -> syn::Result< Self > + { + input.parse::< syn::Token![ = ] >()?; + let value : syn::LitBool = input.parse()?; + Ok( value.value.into() ) + } +} + +impl< Marker > From< bool > for AttributePropertyBoolean< Marker > +{ + #[ inline( always ) ] + fn from( src : bool ) -> Self + { + Self( src, Default::default() ) + } +} + +impl< Marker > From< AttributePropertyBoolean< Marker > > for bool +{ + #[ inline( always ) ] + fn from( src : AttributePropertyBoolean< Marker > ) -> Self + { + src.0 + } +} + +impl< Marker > core::ops::Deref for AttributePropertyBoolean< Marker > +{ + type Target = bool; + + #[ inline( always ) ] + fn deref( &self ) -> &bool + { + &self.0 + } +} + +impl< Marker > AsRef< bool > for AttributePropertyBoolean< Marker > +{ + #[ inline( always ) ] + fn as_ref( &self ) -> &bool + { + &self.0 + } +} diff --git a/module/core/macro_tools/src/attr_prop/boolean_optional.rs b/module/core/macro_tools/src/attr_prop/boolean_optional.rs new file mode 100644 index 0000000000..680803f4c8 --- /dev/null +++ b/module/core/macro_tools/src/attr_prop/boolean_optional.rs @@ -0,0 +1,117 @@ +//! +//! A generic optional boolean attribute property: `Option< bool >`. +//! Defaults to `false`. +//! + +use crate::*; +use former_types::Assign; + +/// Default marker for `AttributePropertyOptionalSingletone`. +/// Used if no marker is defined as parameter. +#[ derive( Debug, Default, Clone, Copy ) ] +pub struct AttributePropertyOptionalBooleanMarker; + +/// A generic optional boolean attribute property: `Option< bool >`. +/// Defaults to `false`. +#[ derive( Debug, Default, Clone, Copy ) ] +pub struct AttributePropertyOptionalBoolean< Marker = AttributePropertyOptionalBooleanMarker >( Option< bool >, ::core::marker::PhantomData< Marker > ); + +impl< Marker > AttributePropertyOptionalBoolean< Marker > +{ + /// Just unwraps and returns the internal data. + #[ inline( always ) ] + pub fn internal( self ) -> Option< bool > + { + self.0 + } + + /// Returns a reference to the internal optional boolean value. + #[ inline( always ) ] + pub fn ref_internal( &self ) -> Option< &bool > + { + self.0.as_ref() + } + +} + +impl< Marker, IntoT > Assign< AttributePropertyOptionalBoolean< Marker >, IntoT > +for AttributePropertyOptionalBoolean< Marker > +where + IntoT : Into< AttributePropertyOptionalBoolean< Marker > >, +{ + /// Inserts value of another instance into the option if it is None, then returns a mutable reference to the contained value. + /// If another instance does is None then do nothing. + #[ inline( always ) ] + fn assign( &mut self, component : IntoT ) + { + let component = component.into(); + match component.0 + { + Some( val ) => { self.0 = Some( val ); }, + None => {}, + } + } +} + +impl< Marker > AttributePropertyComponent for AttributePropertyOptionalBoolean< Marker > +where + Marker : AttributePropertyComponent, +{ + const KEYWORD : &'static str = Marker::KEYWORD; +} + +impl< Marker > syn::parse::Parse for AttributePropertyOptionalBoolean< Marker > +{ + fn parse( input : syn::parse::ParseStream< '_ > ) -> syn::Result< Self > + { + input.parse::< syn::Token![ = ] >()?; + let value : syn::LitBool = input.parse()?; + Ok( value.value.into() ) + } +} + +impl< Marker > From< bool > for AttributePropertyOptionalBoolean< Marker > +{ + #[ inline( always ) ] + fn from( src : bool ) -> Self + { + Self( Some( src ), Default::default() ) + } +} + +impl< Marker > From< Option< bool > > for AttributePropertyOptionalBoolean< Marker > +{ + #[ inline( always ) ] + fn from( src : Option< bool > ) -> Self + { + Self( src, Default::default() ) + } +} + +impl< Marker > From< AttributePropertyOptionalBoolean< Marker > > for Option< bool > +{ + #[ inline( always ) ] + fn from( src : AttributePropertyOptionalBoolean< Marker > ) -> Self + { + src.0 + } +} + +impl< Marker > core::ops::Deref for AttributePropertyOptionalBoolean< Marker > +{ + type Target = Option< bool >; + #[ inline( always ) ] + fn deref( &self ) -> &Option< bool > + { + &self.0 + } +} + +impl< Marker > AsRef< Option< bool > > for AttributePropertyOptionalBoolean< Marker > +{ + #[ inline( always ) ] + fn as_ref( &self ) -> &Option< bool > + { + &self.0 + } +} diff --git a/module/core/macro_tools/src/attr_prop/singletone.rs b/module/core/macro_tools/src/attr_prop/singletone.rs new file mode 100644 index 0000000000..1d55d9ac7c --- /dev/null +++ b/module/core/macro_tools/src/attr_prop/singletone.rs @@ -0,0 +1,108 @@ +//! A generic `bool` attribute property which consists of only keyword. +//! Defaults to `None`. +//! +//! This property can have two states: `true`, or `false`. +//! +//! # Example +//! +//! ```ignore +//! #[ attribute( some ) ] +//! ``` +//! +//! This is useful for attributes that need to enable or disable features or flags. + +use crate::*; +use former_types::Assign; + +/// Default marker for `AttributePropertySingletone`. +/// Used if no marker is defined as parameter. +#[ derive( Debug, Default, Clone, Copy ) ] +pub struct AttributePropertySingletoneMarker; + +/// A generic boolean attribute property which consists of only keyword. +/// This property can have two states: `true`, or `false`. +/// Defaults to `false`. +/// +/// Unlike other properties, it does not implement parse, because it consists only of keyword which should be parsed outside of the property. +#[ derive( Debug, Default, Clone, Copy ) ] +pub struct AttributePropertySingletone< Marker = AttributePropertySingletoneMarker > +( + bool, + ::core::marker::PhantomData< Marker >, +); + +impl< Marker > AttributePropertySingletone< Marker > +{ + + /// Unwraps and returns the internal optional boolean value. + #[ inline( always ) ] + pub fn internal( self ) -> bool + { + self.0 + } + + /// Returns a reference to the internal optional boolean value. + #[ inline( always ) ] + pub fn ref_internal( &self ) -> &bool + { + &self.0 + } + +} + +impl< Marker, IntoT > Assign< AttributePropertySingletone< Marker >, IntoT > +for AttributePropertySingletone< Marker > +where + IntoT : Into< AttributePropertySingletone< Marker > >, +{ + #[ inline( always ) ] + fn assign( &mut self, component : IntoT ) + { + *self = component.into(); + } +} + +impl< Marker > AttributePropertyComponent for AttributePropertySingletone< Marker > +where + Marker : AttributePropertyComponent, +{ + const KEYWORD : &'static str = Marker::KEYWORD; +} + +impl< Marker > From< bool > for AttributePropertySingletone< Marker > +{ + #[ inline( always ) ] + fn from( src : bool ) -> Self + { + Self( src, Default::default() ) + } +} + +impl< Marker > From< AttributePropertySingletone< Marker > > for bool +{ + #[ inline( always ) ] + fn from( src : AttributePropertySingletone< Marker > ) -> Self + { + src.0 + } +} + +impl< Marker > core::ops::Deref for AttributePropertySingletone< Marker > +{ + type Target = bool; + + #[ inline( always ) ] + fn deref( &self ) -> &bool + { + &self.0 + } +} + +impl< Marker > AsRef< bool > for AttributePropertySingletone< Marker > +{ + #[ inline( always ) ] + fn as_ref( &self ) -> &bool + { + &self.0 + } +} diff --git a/module/core/macro_tools/src/attr_prop/singletone_optional.rs b/module/core/macro_tools/src/attr_prop/singletone_optional.rs new file mode 100644 index 0000000000..39c3dd9940 --- /dev/null +++ b/module/core/macro_tools/src/attr_prop/singletone_optional.rs @@ -0,0 +1,139 @@ +//! A generic `Option< bool >` attribute property which consists of only keyword. +//! Defaults to `None`. +//! +//! This property can have three states: `None`, `Some( true )`, or `Some( false )`. +//! It parses `on` and `off` keywords to represent `Some( true )` and `Some( false )` respectively. +//! +//! # Example +//! +//! ```ignore +//! #[ attribute( on) ] +//! #[ attribute( off ) ] +//! ``` +//! +//! This is useful for attributes that need to enable or disable features or flags. + +use crate::*; +use former_types::Assign; + +/// Default marker for `AttributePropertyOptionalSingletone`. +/// Used if no marker is defined as parameter. +#[ derive( Debug, Default, Clone, Copy ) ] +pub struct AttributePropertyOptionalSingletoneMarker; + +/// A generic attribute property for switching on/off. +/// Has 3 states: `None`, `Some( true )`, `Some( false )`. +/// Defaults to `None`. +/// +/// Unlike [`AttributePropertyOptionalBoolean`], it "understands" `on`, `off` keywords during parsing. +/// For example: `#[ attribute( on ) ]` and `#[ attribute( off )]`. +/// As a consequence, the property has two keywords. +#[ derive( Debug, Default, Clone, Copy ) ] +pub struct AttributePropertyOptionalSingletone< Marker = AttributePropertyOptionalSingletoneMarker > +( + Option< bool >, + ::core::marker::PhantomData< Marker >, +); + +impl< Marker > AttributePropertyOptionalSingletone< Marker > +{ + + /// Return bool value: on/off, use argument as default if it's `None`. + #[ inline ] + pub fn value( self, default : bool ) -> bool + { + if self.0.is_none() + { + return default; + } + self.0.unwrap() + } + + /// Unwraps and returns the internal optional boolean value. + #[ inline( always ) ] + pub fn internal( self ) -> Option< bool > + { + self.0 + } + + /// Returns a reference to the internal optional boolean value. + #[ inline( always ) ] + pub fn ref_internal( &self ) -> Option< &bool > + { + self.0.as_ref() + } + +} + +impl< Marker, IntoT > Assign< AttributePropertyOptionalSingletone< Marker >, IntoT > +for AttributePropertyOptionalSingletone< Marker > +where + IntoT : Into< AttributePropertyOptionalSingletone< Marker > >, +{ + /// Inserts value of another instance into the option if it is None, then returns a mutable reference to the contained value. + /// If another instance does is None then do nothing. + #[ inline( always ) ] + fn assign( &mut self, component : IntoT ) + { + let component = component.into(); + match component.0 + { + Some( val ) => { self.0 = Some( val ); }, + None => {}, + } + } +} + +impl< Marker > AttributePropertyComponent for AttributePropertyOptionalSingletone< Marker > +where + Marker : AttributePropertyComponent, +{ + const KEYWORD : &'static str = Marker::KEYWORD; +} + +impl< Marker > From< bool > for AttributePropertyOptionalSingletone< Marker > +{ + #[ inline( always ) ] + fn from( src : bool ) -> Self + { + Self( Some( src ), Default::default() ) + } +} + +impl< Marker > From< Option< bool > > for AttributePropertyOptionalSingletone< Marker > +{ + #[ inline( always ) ] + fn from( src : Option< bool > ) -> Self + { + Self( src, Default::default() ) + } +} + +impl< Marker > From< AttributePropertyOptionalSingletone< Marker > > for Option< bool > +{ + #[ inline( always ) ] + fn from( src : AttributePropertyOptionalSingletone< Marker > ) -> Self + { + src.0 + } +} + +impl< Marker > core::ops::Deref for AttributePropertyOptionalSingletone< Marker > +{ + type Target = Option< bool >; + + #[ inline( always ) ] + fn deref( &self ) -> &Option< bool > + { + &self.0 + } +} + +impl< Marker > AsRef< Option< bool > > for AttributePropertyOptionalSingletone< Marker > +{ + #[ inline( always ) ] + fn as_ref( &self ) -> &Option< bool > + { + &self.0 + } +} diff --git a/module/core/macro_tools/src/attr_prop/syn.rs b/module/core/macro_tools/src/attr_prop/syn.rs new file mode 100644 index 0000000000..c60a21cfdd --- /dev/null +++ b/module/core/macro_tools/src/attr_prop/syn.rs @@ -0,0 +1,115 @@ +//! +//! Property of an attribute which simply wraps one of the standard `syn` types. +//! + +use crate::*; +use former_types::Assign; + +/// Default marker for `AttributePropertySyn`. +/// Used if no marker is defined as parameter. +#[ derive( Debug, Default, Clone, Copy ) ] +pub struct AttributePropertySynMarker; + +/// +/// Property of an attribute which simply wraps one of the standard `syn` types. +/// + +#[ derive( Debug, Clone ) ] +pub struct AttributePropertySyn< T, Marker = AttributePropertySynMarker >( T, ::core::marker::PhantomData< Marker > ) +where + T : syn::parse::Parse + quote::ToTokens; + +impl< T, Marker > AttributePropertySyn< T, Marker > +where + T : syn::parse::Parse + quote::ToTokens, +{ + /// Just unwraps and returns the internal data. + // #[ allow( dead_code ) ] + #[ inline( always ) ] + pub fn internal( self ) -> T + { + self.0 + } + + /// Returns a reference to the internal data. + // #[ allow( dead_code ) ] + #[ inline( always ) ] + pub fn ref_internal( &self ) -> &T + { + &self.0 + } +} + +impl< T, Marker, IntoT > Assign< AttributePropertySyn< T, Marker >, IntoT > +for AttributePropertySyn< T, Marker > +where + T : syn::parse::Parse + quote::ToTokens, + IntoT : Into< AttributePropertySyn< T, Marker > >, +{ + #[ inline( always ) ] + fn assign( &mut self, component : IntoT ) + { + *self = component.into(); + } +} + +impl< T, Marker > AttributePropertyComponent for AttributePropertySyn< T, Marker > +where + T : syn::parse::Parse + quote::ToTokens, + Marker : AttributePropertyComponent, +{ + const KEYWORD : &'static str = Marker::KEYWORD; +} + +impl< T, Marker > syn::parse::Parse for AttributePropertySyn< T, Marker > +where + T : syn::parse::Parse + quote::ToTokens, +{ + fn parse( input : syn::parse::ParseStream< '_ > ) -> syn::Result< Self > + { + input.parse::< syn::Token![ = ] >()?; + let value : T = input.parse()?; + Ok( value.into() ) + } +} + +impl< T, Marker > quote::ToTokens for AttributePropertySyn< T, Marker > +where + T : syn::parse::Parse + quote::ToTokens, +{ + fn to_tokens( &self, tokens : &mut proc_macro2::TokenStream ) + { + self.0.to_tokens( tokens ); + } +} + +impl< T, Marker > core::ops::Deref for AttributePropertySyn< T, Marker > +where T : syn::parse::Parse + quote::ToTokens +{ + type Target = T; + #[ inline( always ) ] + fn deref( &self ) -> &T + { + &self.0 + } +} + +impl< T, Marker > AsRef< T > for AttributePropertySyn< T, Marker > +where T : syn::parse::Parse + quote::ToTokens +{ + #[ inline( always ) ] + fn as_ref( &self ) -> &T + { + &self.0 + } +} + +impl< T, Marker > From< T > for AttributePropertySyn< T, Marker > +where T : syn::parse::Parse + quote::ToTokens +{ + #[ inline( always ) ] + fn from( src : T ) -> Self + { + Self( src, Default::default() ) + } +} diff --git a/module/core/macro_tools/src/attr_prop/syn_optional.rs b/module/core/macro_tools/src/attr_prop/syn_optional.rs new file mode 100644 index 0000000000..d595e9496a --- /dev/null +++ b/module/core/macro_tools/src/attr_prop/syn_optional.rs @@ -0,0 +1,160 @@ +//! +//! Property of an attribute which simply wraps one of the standard `syn` types and keeps it optional. +//! + +use crate::*; +use former_types::Assign; + +/// Default marker for `AttributePropertyOptionalSyn`. +/// Used if no marker is defined as parameter. +#[ derive( Debug, Default, Clone, Copy ) ] +pub struct AttributePropertyOptionalSynMarker; + +/// +/// Property of an attribute which simply wraps one of the standard `syn` types and keeps it optional. +/// + +#[ derive( Debug, Clone ) ] +pub struct AttributePropertyOptionalSyn< T, Marker = AttributePropertyOptionalSynMarker >( Option< T >, ::core::marker::PhantomData< Marker > ) +where + T : syn::parse::Parse + quote::ToTokens; + +impl< T, Marker > AttributePropertyOptionalSyn< T, Marker > +where + T : syn::parse::Parse + quote::ToTokens, +{ + /// Just unwraps and returns the internal data. + #[ inline( always ) ] + pub fn internal( self ) -> Option< T > + { + self.0 + } + + /// Returns an Option reference to the internal data. + #[ inline( always ) ] + pub fn ref_internal( &self ) -> Option< &T > + { + self.0.as_ref() + } +} + +impl< T, Marker, IntoT > Assign< AttributePropertyOptionalSyn< T, Marker >, IntoT > +for AttributePropertyOptionalSyn< T, Marker > +where + T : syn::parse::Parse + quote::ToTokens, + IntoT : Into< AttributePropertyOptionalSyn< T, Marker > >, +{ + /// Inserts value of another instance into the option if it is None, then returns a mutable reference to the contained value. + /// If another instance does is None then do nothing. + #[ inline( always ) ] + fn assign( &mut self, component : IntoT ) + { + let component = component.into(); + match component.0 + { + Some( val ) => { self.0 = Some( val ); }, + None => {}, + } + } +} + +impl< T, Marker > AttributePropertyComponent for AttributePropertyOptionalSyn< T, Marker > +where + T : syn::parse::Parse + quote::ToTokens, + Marker : AttributePropertyComponent, +{ + const KEYWORD : &'static str = Marker::KEYWORD; +} + +impl< T, Marker > Default for AttributePropertyOptionalSyn< T, Marker > +where + T : syn::parse::Parse + quote::ToTokens, +{ + fn default() -> Self + { + Self( None, Default::default() ) + } +} + +impl< T, Marker > syn::parse::Parse for AttributePropertyOptionalSyn< T, Marker > +where + T : syn::parse::Parse + quote::ToTokens, +{ + fn parse( input : syn::parse::ParseStream< '_ > ) -> syn::Result< Self > + { + input.parse::< syn::Token![ = ] >()?; + let value : T = input.parse()?; + Ok( value.into() ) + } +} + +impl< T, Marker > quote::ToTokens for AttributePropertyOptionalSyn< T, Marker > +where + T : syn::parse::Parse + quote::ToTokens, +{ + fn to_tokens( &self, tokens : &mut proc_macro2::TokenStream ) + { + self.0.to_tokens( tokens ); + } +} + +impl< T, Marker > core::ops::Deref for AttributePropertyOptionalSyn< T, Marker > +where T : syn::parse::Parse + quote::ToTokens +{ + type Target = Option< T >; + #[ inline( always ) ] + fn deref( &self ) -> &Option< T > + { + &self.0 + } +} + +impl< T, Marker > AsRef< Option< T > > for AttributePropertyOptionalSyn< T, Marker > +where T : syn::parse::Parse + quote::ToTokens +{ + #[ inline( always ) ] + fn as_ref( &self ) -> &Option< T > + { + &self.0 + } +} + +impl< T, Marker > From< T > for AttributePropertyOptionalSyn< T, Marker > +where T : syn::parse::Parse + quote::ToTokens +{ + #[ inline( always ) ] + fn from( src : T ) -> Self + { + Self( Some( src ), Default::default() ) + } +} + +impl< T, Marker > From< Option< T > > for AttributePropertyOptionalSyn< T, Marker > +where T : syn::parse::Parse + quote::ToTokens +{ + #[ inline( always ) ] + fn from( src : Option< T > ) -> Self + { + Self( src, Default::default() ) + } +} + +impl< T, Marker > From< AttributePropertyOptionalSyn< T, Marker > > for Option< T > +where T : syn::parse::Parse + quote::ToTokens +{ + #[ inline( always ) ] + fn from( src : AttributePropertyOptionalSyn< T, Marker > ) -> Self + { + src.0 + } +} + +impl< 'a, T, Marker > From< &'a AttributePropertyOptionalSyn< T, Marker > > for Option< &'a T > +where T : syn::parse::Parse + quote::ToTokens +{ + #[ inline( always ) ] + fn from( src : &'a AttributePropertyOptionalSyn< T, Marker > ) -> Self + { + src.0.as_ref() + } +} diff --git a/module/core/macro_tools/src/lib.rs b/module/core/macro_tools/src/lib.rs index b1ababf64b..85bafc8eb4 100644 --- a/module/core/macro_tools/src/lib.rs +++ b/module/core/macro_tools/src/lib.rs @@ -170,18 +170,23 @@ pub mod prelude #[ doc( inline ) ] #[ allow( unused_imports ) ] pub use ::syn; + #[ doc( inline ) ] #[ allow( unused_imports ) ] pub use ::proc_macro2; + #[ doc( inline ) ] #[ allow( unused_imports ) ] pub use ::quote; + #[ doc( inline ) ] #[ allow( unused_imports ) ] - pub use ::quote::quote as qt; - #[ doc( inline ) ] - #[ allow( unused_imports ) ] - pub use ::syn::parse_quote as parse_qt; + pub use ::quote:: + { + quote as qt, + format_ident, + }; + #[ doc( inline ) ] #[ allow( unused_imports ) ] pub use ::syn::spanned::Spanned; @@ -199,7 +204,9 @@ pub mod prelude parenthesized, parse_macro_input, parse_quote, + parse_quote as parse_qt, parse_quote_spanned, + parse_quote_spanned as parse_qt_spanned, }; #[ doc( inline ) ] diff --git a/module/core/macro_tools/tests/inc/attr_prop_test.rs b/module/core/macro_tools/tests/inc/attr_prop_test.rs index 8d2ff6c559..e2fdb5ecb6 100644 --- a/module/core/macro_tools/tests/inc/attr_prop_test.rs +++ b/module/core/macro_tools/tests/inc/attr_prop_test.rs @@ -2,7 +2,7 @@ use super::*; use quote::ToTokens; #[ test ] -fn test_attribute_property_boolean() +fn attr_prop_test() { #[ derive( Debug, Default, Clone, Copy ) ] @@ -46,7 +46,6 @@ fn test_attribute_property_boolean() if lookahead.peek( syn::Ident ) { let ident : syn::Ident = input.parse()?; - input.parse::< syn::Token![=] >()?; match ident.to_string().as_str() { DebugMarker::KEYWORD => debug = input.parse()?, @@ -70,7 +69,7 @@ fn test_attribute_property_boolean() } } - let input : syn::Attribute = syn::parse_quote!( #[ attribute( enabled = true, debug = false ) ] ); + let input : syn::Attribute = syn::parse_quote!( #[ attribute( enabled = true ) ] ); let meta = match input.meta { syn::Meta::List( meta_list ) => meta_list, @@ -88,7 +87,7 @@ fn test_attribute_property_boolean() let attr : AttributePropertyBoolean< DebugMarker > = false.into(); assert_eq!( attr.internal(), false ); - let input : syn::Attribute = syn::parse_quote!( #[ attribute( enabled = true, debug = false ) ] ); + let input : syn::Attribute = syn::parse_quote!( #[ attribute( enabled = true ) ] ); let meta = match input.meta { syn::Meta::List( meta_list ) => meta_list, @@ -99,4 +98,16 @@ fn test_attribute_property_boolean() let parsed : MyAttributes = syn::parse2( nested_meta_stream ).unwrap(); assert_eq!( parsed.enabled.internal(), true ); assert_eq!( parsed.debug.internal(), false ); + +} + +#[ test ] +fn attribute_property_enabled() +{ + // Test default value + let attr : AttributePropertyOptionalSingletone = Default::default(); + assert_eq!( attr.internal(), None ); + assert_eq!( attr.value( true ), true ); + assert_eq!( attr.value( false ), false ); + } diff --git a/module/core/mod_interface/Cargo.toml b/module/core/mod_interface/Cargo.toml index 381551f5d5..4876619e96 100644 --- a/module/core/mod_interface/Cargo.toml +++ b/module/core/mod_interface/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mod_interface" -version = "0.19.0" +version = "0.20.0" edition = "2021" authors = [ "Kostiantyn Wandalen ", diff --git a/module/core/mod_interface_meta/Cargo.toml b/module/core/mod_interface_meta/Cargo.toml index 62b4c26d8e..b8e13dae71 100644 --- a/module/core/mod_interface_meta/Cargo.toml +++ b/module/core/mod_interface_meta/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mod_interface_meta" -version = "0.19.0" +version = "0.20.0" edition = "2021" authors = [ "Kostiantyn Wandalen ", diff --git a/module/core/process_tools/Cargo.toml b/module/core/process_tools/Cargo.toml index 8620c11659..20325bebf8 100644 --- a/module/core/process_tools/Cargo.toml +++ b/module/core/process_tools/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "process_tools" -version = "0.4.0" +version = "0.5.0" edition = "2021" authors = [ "Kostiantyn Wandalen ", diff --git a/module/core/proper_path_tools/Cargo.toml b/module/core/proper_path_tools/Cargo.toml index 9122db09b5..7f432561a1 100644 --- a/module/core/proper_path_tools/Cargo.toml +++ b/module/core/proper_path_tools/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "proper_path_tools" -version = "0.5.0" +version = "0.6.0" edition = "2021" authors = [ "Kostiantyn Wandalen ", diff --git a/module/core/strs_tools/Cargo.toml b/module/core/strs_tools/Cargo.toml index 1e4263e517..1bd6baf56f 100644 --- a/module/core/strs_tools/Cargo.toml +++ b/module/core/strs_tools/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "strs_tools" -version = "0.12.0" +version = "0.13.0" edition = "2021" authors = [ "Kostiantyn Wandalen ", diff --git a/module/core/variadic_from/Cargo.toml b/module/core/variadic_from/Cargo.toml index 4bd87fb11b..3a8aac6c6e 100644 --- a/module/core/variadic_from/Cargo.toml +++ b/module/core/variadic_from/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "variadic_from" -version = "0.17.0" +version = "0.18.0" edition = "2021" authors = [ "Kostiantyn Wandalen ", diff --git a/module/move/crates_tools/Cargo.toml b/module/move/crates_tools/Cargo.toml index e97cdc78b9..4120a358df 100644 --- a/module/move/crates_tools/Cargo.toml +++ b/module/move/crates_tools/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "crates_tools" -version = "0.9.0" +version = "0.10.0" edition = "2021" authors = [ "Kostiantyn Wandalen ", diff --git a/module/move/wca/Cargo.toml b/module/move/wca/Cargo.toml index 397ec27c94..2d8184148e 100644 --- a/module/move/wca/Cargo.toml +++ b/module/move/wca/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wca" -version = "0.16.0" +version = "0.17.0" edition = "2021" authors = [ "Kostiantyn Wandalen ", diff --git a/module/move/wca/src/ca/aggregator.rs b/module/move/wca/src/ca/aggregator.rs index 8336b1df29..1d81a4e945 100644 --- a/module/move/wca/src/ca/aggregator.rs +++ b/module/move/wca/src/ca/aggregator.rs @@ -26,7 +26,7 @@ pub( crate ) mod private for_lib::*, }; use wtools::Itertools; - + /// Order of commands and properties. #[ derive( Debug, Default, Clone, Copy, Eq, PartialOrd, PartialEq ) ] pub enum Order @@ -112,7 +112,7 @@ pub( crate ) mod private #[ derive( Debug ) ] #[ derive( former::Former ) ] #[ storage_fields( help_generator : HelpGeneratorFn, help_variants : HashSet< HelpVariants >, order : Order ) ] - #[ mutator( custom = true ) ] + #[ mutator( custom ) ] // #[ debug ] pub struct CommandsAggregator { @@ -122,7 +122,7 @@ pub( crate ) mod private #[ former( default = Parser ) ] parser : Parser, - #[ scalar( setter = false, hint = false ) ] + #[ scalar( setter = false ) ] #[ former( default = Executor::former().form() ) ] executor : Executor, diff --git a/module/move/wca/src/ca/facade.rs b/module/move/wca/src/ca/facade.rs index a5a466cba6..cdc9edb599 100644 --- a/module/move/wca/src/ca/facade.rs +++ b/module/move/wca/src/ca/facade.rs @@ -65,7 +65,7 @@ pub( crate ) mod private /// The name of the property. pub name : &'a str, /// The hint for the property. - pub hint : &'a str, + pub debug : &'a str, /// The tag representing the property's type. pub tag : Type, } diff --git a/module/move/wca/src/ca/grammar/command.rs b/module/move/wca/src/ca/grammar/command.rs index 3d3e5cd2b4..8357eb9a54 100644 --- a/module/move/wca/src/ca/grammar/command.rs +++ b/module/move/wca/src/ca/grammar/command.rs @@ -1,7 +1,7 @@ pub( crate ) mod private { use crate::*; - + use std::collections::{ BTreeMap, HashMap }; use former::{ Former, StoragePreform }; use wtools::Itertools; @@ -113,18 +113,18 @@ pub( crate ) mod private #[ former( default = Routine::from( Handler::from( || { panic!( "No routine available: A handler function for the command is missing" ) } ) ) ) ] pub routine : Routine, } - + impl Command { pub( crate ) fn properties( &self, order : Order ) -> Vec< ( &String, &ValueDescription ) > { - match order + match order { - Order::Nature => + Order::Nature => { self.properties.iter().map( | ( key, value ) | ( &key.name, value ) ).collect() } - Order::Lexicography => + Order::Lexicography => { self.properties.iter().map( | ( key, value ) | ( &key.name, value ) ).sorted_by_key( | ( k, _ ) | *k ).collect() } diff --git a/module/move/wca/src/ca/grammar/dictionary.rs b/module/move/wca/src/ca/grammar/dictionary.rs index 57ad3f1d71..5e213dcbf4 100644 --- a/module/move/wca/src/ca/grammar/dictionary.rs +++ b/module/move/wca/src/ca/grammar/dictionary.rs @@ -26,7 +26,7 @@ pub( crate ) mod private impl std::borrow::Borrow< String > for CommandName { - fn borrow( &self ) -> &String + fn borrow( &self ) -> &String { &self.name } @@ -40,8 +40,8 @@ pub( crate ) mod private { Ordering::Equal } - else - { + else + { self.id.cmp( &other.id ) } } @@ -69,9 +69,9 @@ pub( crate ) mod private #[ derive( Debug, Default, Former, Clone ) ] pub struct Dictionary { - #[ scalar( setter = false, hint = false ) ] + #[ scalar( setter = false ) ] pub( crate ) commands : BTreeMap< CommandName, Command >, - #[ scalar( setter = false, hint = false ) ] + #[ scalar( setter = false ) ] dictionary_last_id : usize, pub( crate ) order : Order, } @@ -122,7 +122,7 @@ pub( crate ) mod private { self.commands.iter().find( | ( k, _ ) | k.name == name.to_string() ).map( | ( _, v ) | v ) } - + /// Find commands that match a given name part. /// /// This function accepts a `name_part` parameter which is of generic type `NamePart`. diff --git a/module/move/willbe/Cargo.toml b/module/move/willbe/Cargo.toml index cd58c869d2..27fed31983 100644 --- a/module/move/willbe/Cargo.toml +++ b/module/move/willbe/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "willbe" -version = "0.10.0" +version = "0.11.0" edition = "2021" authors = [ "Kostiantyn Wandalen ", diff --git a/module/move/willbe/src/entity/package.rs b/module/move/willbe/src/entity/package.rs index 379e8a2bfd..9e1f281ebc 100644 --- a/module/move/willbe/src/entity/package.rs +++ b/module/move/willbe/src/entity/package.rs @@ -523,7 +523,7 @@ mod private /// how to build and where to publish the package amongst other instructions. The `#[setter( false )]` /// attribute indicates that there is no setter method for the `plans` variable and it can only be modified /// within the struct. - #[ scalar( setter = false, hint = false ) ] + #[ scalar( setter = false ) ] pub plans : Vec< PackagePublishInstruction >, } @@ -612,7 +612,7 @@ mod private self.storage.base_temp_dir = path; self } - + pub fn package< IntoPackage >( mut self, package : IntoPackage ) -> Self where IntoPackage : Into< Package >, diff --git a/module/move/willbe/src/tool/template.rs b/module/move/willbe/src/tool/template.rs index 44f0e4bb9e..ae07683d4b 100644 --- a/module/move/willbe/src/tool/template.rs +++ b/module/move/willbe/src/tool/template.rs @@ -303,7 +303,7 @@ mod private { /// Stores all file descriptors for current template. #[ subform_entry( setter = true ) ] - #[ scalar( setter = false, hint = false ) ] + #[ scalar( setter = false ) ] pub files : Vec< TemplateFileDescriptor >, }