From 5a5529991dbba69fd31b2efe84180ec39ee5e69b Mon Sep 17 00:00:00 2001 From: Egor <82723465+Inkvisto@users.noreply.github.com> Date: Mon, 15 Jul 2024 18:48:07 +0300 Subject: [PATCH] READY: IndexMut macros (#1409) derive_tools: IndexMut macros --- module/core/derive_tools/Cargo.toml | 3 +- module/core/derive_tools/build.rs | 2 + module/core/derive_tools/src/lib.rs | 2 - .../tests/inc/index_mut/compiletime/enum.rs | 13 + .../inc/index_mut/compiletime/enum.stderr | 7 + .../tests/inc/index_mut/compiletime/struct.rs | 14 + .../inc/index_mut/compiletime/struct.stderr | 8 + .../compiletime/struct_named_empty.rs | 10 + .../compiletime/struct_named_empty.stderr | 7 + .../inc/index_mut/compiletime/struct_unit.rs | 9 + .../index_mut/compiletime/struct_unit.stderr | 7 + .../only_test/struct_multiple_named.rs | 20 + .../only_test/struct_multiple_tuple.rs | 14 + .../inc/index_mut/only_test/struct_named.rs | 18 + .../inc/index_mut/only_test/struct_tuple.rs | 14 + .../tests/inc/index_mut/struct_collisions.rs | 22 ++ .../index_mut/struct_multiple_named_field.rs | 14 + .../index_mut/struct_multiple_named_item.rs | 15 + .../index_mut/struct_multiple_named_manual.rs | 30 ++ .../inc/index_mut/struct_multiple_tuple.rs | 15 + .../index_mut/struct_multiple_tuple_manual.rs | 27 ++ .../tests/inc/index_mut/struct_named.rs | 12 + .../inc/index_mut/struct_named_manual.rs | 28 ++ .../tests/inc/index_mut/struct_tuple.rs | 12 + .../inc/index_mut/struct_tuple_manual.rs | 26 ++ module/core/derive_tools/tests/inc/mod.rs | 39 +- module/core/derive_tools_meta/Cargo.toml | 3 + module/core/derive_tools_meta/src/derive.rs | 2 + .../derive_tools_meta/src/derive/index_mut.rs | 362 ++++++++++++++++++ module/core/derive_tools_meta/src/lib.rs | 73 ++++ 30 files changed, 824 insertions(+), 4 deletions(-) create mode 100644 module/core/derive_tools/tests/inc/index_mut/compiletime/enum.rs create mode 100644 module/core/derive_tools/tests/inc/index_mut/compiletime/enum.stderr create mode 100644 module/core/derive_tools/tests/inc/index_mut/compiletime/struct.rs create mode 100644 module/core/derive_tools/tests/inc/index_mut/compiletime/struct.stderr create mode 100644 module/core/derive_tools/tests/inc/index_mut/compiletime/struct_named_empty.rs create mode 100644 module/core/derive_tools/tests/inc/index_mut/compiletime/struct_named_empty.stderr create mode 100644 module/core/derive_tools/tests/inc/index_mut/compiletime/struct_unit.rs create mode 100644 module/core/derive_tools/tests/inc/index_mut/compiletime/struct_unit.stderr create mode 100644 module/core/derive_tools/tests/inc/index_mut/only_test/struct_multiple_named.rs create mode 100644 module/core/derive_tools/tests/inc/index_mut/only_test/struct_multiple_tuple.rs create mode 100644 module/core/derive_tools/tests/inc/index_mut/only_test/struct_named.rs create mode 100644 module/core/derive_tools/tests/inc/index_mut/only_test/struct_tuple.rs create mode 100644 module/core/derive_tools/tests/inc/index_mut/struct_collisions.rs create mode 100644 module/core/derive_tools/tests/inc/index_mut/struct_multiple_named_field.rs create mode 100644 module/core/derive_tools/tests/inc/index_mut/struct_multiple_named_item.rs create mode 100644 module/core/derive_tools/tests/inc/index_mut/struct_multiple_named_manual.rs create mode 100644 module/core/derive_tools/tests/inc/index_mut/struct_multiple_tuple.rs create mode 100644 module/core/derive_tools/tests/inc/index_mut/struct_multiple_tuple_manual.rs create mode 100644 module/core/derive_tools/tests/inc/index_mut/struct_named.rs create mode 100644 module/core/derive_tools/tests/inc/index_mut/struct_named_manual.rs create mode 100644 module/core/derive_tools/tests/inc/index_mut/struct_tuple.rs create mode 100644 module/core/derive_tools/tests/inc/index_mut/struct_tuple_manual.rs create mode 100644 module/core/derive_tools_meta/src/derive/index_mut.rs diff --git a/module/core/derive_tools/Cargo.toml b/module/core/derive_tools/Cargo.toml index 59bab6fe50..30813536c8 100644 --- a/module/core/derive_tools/Cargo.toml +++ b/module/core/derive_tools/Cargo.toml @@ -152,7 +152,7 @@ derive_error = [ "derive_more", "derive_more/std", "derive_more/error" ] # derive_reflect = [ "derive_tools_meta/derive_reflect" ] # derive_index = [ "derive_more", "derive_more/std", "derive_more/index" ] -derive_index_mut = [ "derive_more", "derive_more/std", "derive_more/index_mut" ] +# derive_index_mut = [ "derive_more", "derive_more/std", "derive_more/index_mut" ] # derive_inner_from = [ "derive_more", "derive_more/into" ] derive_into_iterator = [ "derive_more", "derive_more/std", "derive_more/into_iterator" ] # derive_iterator = [ "derive_more", "derive_more/iterator" ] @@ -181,6 +181,7 @@ derive_clone_dyn = [ "clone_dyn/enabled" ] derive_from = [ "derive_tools_meta/derive_from" ] derive_index = [ "derive_tools_meta/derive_index" ] +derive_index_mut = [ "derive_tools_meta/derive_index_mut" ] derive_inner_from = [ "derive_tools_meta/derive_inner_from" ] derive_new = [ "derive_tools_meta/derive_new" ] diff --git a/module/core/derive_tools/build.rs b/module/core/derive_tools/build.rs index afc1ca3107..c6e66c36b0 100644 --- a/module/core/derive_tools/build.rs +++ b/module/core/derive_tools/build.rs @@ -22,6 +22,7 @@ fn main() feature = "derive_deref_mut", feature = "derive_from", feature = "derive_index", + feature = "derive_index_mut", feature = "derive_inner_from", feature = "derive_variadic_from", feature = "derive_reflect", @@ -38,6 +39,7 @@ fn main() feature = "derive_deref_mut", feature = "derive_from", feature = "derive_index", + feature = "derive_index_mut", feature = "derive_inner_from", feature = "derive_variadic_from", feature = "derive_reflect", diff --git a/module/core/derive_tools/src/lib.rs b/module/core/derive_tools/src/lib.rs index 50a2fe8ed6..bab82fa7c9 100644 --- a/module/core/derive_tools/src/lib.rs +++ b/module/core/derive_tools/src/lib.rs @@ -43,8 +43,6 @@ mod derive_more pub use ::derive_more::Constructor; #[ cfg( feature = "derive_error" ) ] pub use ::derive_more::Error; - #[ cfg( feature = "derive_index_mut" ) ] - pub use ::derive_more::IndexMut; #[ cfg( feature = "derive_into" ) ] pub use ::derive_more::Into; // #[ cfg( feature = "derive_iterator" ) ] diff --git a/module/core/derive_tools/tests/inc/index_mut/compiletime/enum.rs b/module/core/derive_tools/tests/inc/index_mut/compiletime/enum.rs new file mode 100644 index 0000000000..29357cf2a3 --- /dev/null +++ b/module/core/derive_tools/tests/inc/index_mut/compiletime/enum.rs @@ -0,0 +1,13 @@ +use derive_tools::IndexMut; + +#[ derive( IndexMut ) ] +enum Enum< T > +{ + Nothing, + #[ index ] + IndexVector( Vec< T > ) +} + +fn main() +{ +} diff --git a/module/core/derive_tools/tests/inc/index_mut/compiletime/enum.stderr b/module/core/derive_tools/tests/inc/index_mut/compiletime/enum.stderr new file mode 100644 index 0000000000..47952cbcbe --- /dev/null +++ b/module/core/derive_tools/tests/inc/index_mut/compiletime/enum.stderr @@ -0,0 +1,7 @@ +error: proc-macro derive panicked + --> tests/inc/index_mut/compiletime/enum.rs:3:12 + | +3 | #[ derive( IndexMut ) ] + | ^^^^^^^^ + | + = help: message: not implemented: IndexMut not implemented for Enum diff --git a/module/core/derive_tools/tests/inc/index_mut/compiletime/struct.rs b/module/core/derive_tools/tests/inc/index_mut/compiletime/struct.rs new file mode 100644 index 0000000000..119c1ec1ba --- /dev/null +++ b/module/core/derive_tools/tests/inc/index_mut/compiletime/struct.rs @@ -0,0 +1,14 @@ +use derive_tools::IndexMut; + +#[ derive( IndexMut ) ] +struct StructMultipleNamed< T > +{ + #[ index ] + a : Vec< T >, + #[ index ] + b : Vec< T >, +} + +fn main() +{ +} diff --git a/module/core/derive_tools/tests/inc/index_mut/compiletime/struct.stderr b/module/core/derive_tools/tests/inc/index_mut/compiletime/struct.stderr new file mode 100644 index 0000000000..ebe09c13f9 --- /dev/null +++ b/module/core/derive_tools/tests/inc/index_mut/compiletime/struct.stderr @@ -0,0 +1,8 @@ +error: Only one field can include #[ index ] derive macro + --> tests/inc/index_mut/compiletime/struct.rs:6:3 + | +6 | / #[ index ] +7 | | a : Vec< T >, +8 | | #[ index ] +9 | | b : Vec< T >, + | |_______________^ diff --git a/module/core/derive_tools/tests/inc/index_mut/compiletime/struct_named_empty.rs b/module/core/derive_tools/tests/inc/index_mut/compiletime/struct_named_empty.rs new file mode 100644 index 0000000000..898f8f3dfa --- /dev/null +++ b/module/core/derive_tools/tests/inc/index_mut/compiletime/struct_named_empty.rs @@ -0,0 +1,10 @@ +use derive_tools::IndexMut; + +#[ derive( IndexMut ) ] +struct EmptyStruct +{ +} + +fn main() +{ +} diff --git a/module/core/derive_tools/tests/inc/index_mut/compiletime/struct_named_empty.stderr b/module/core/derive_tools/tests/inc/index_mut/compiletime/struct_named_empty.stderr new file mode 100644 index 0000000000..08eabad5aa --- /dev/null +++ b/module/core/derive_tools/tests/inc/index_mut/compiletime/struct_named_empty.stderr @@ -0,0 +1,7 @@ +error: proc-macro derive panicked + --> tests/inc/index_mut/compiletime/struct_named_empty.rs:3:12 + | +3 | #[ derive( IndexMut ) ] + | ^^^^^^^^ + | + = help: message: not implemented: IndexMut not implemented for Unit diff --git a/module/core/derive_tools/tests/inc/index_mut/compiletime/struct_unit.rs b/module/core/derive_tools/tests/inc/index_mut/compiletime/struct_unit.rs new file mode 100644 index 0000000000..ce59c37b15 --- /dev/null +++ b/module/core/derive_tools/tests/inc/index_mut/compiletime/struct_unit.rs @@ -0,0 +1,9 @@ +use derive_tools::IndexMut; + +#[ derive( IndexMut ) ] +struct StructUnit; + +fn main() +{ + +} diff --git a/module/core/derive_tools/tests/inc/index_mut/compiletime/struct_unit.stderr b/module/core/derive_tools/tests/inc/index_mut/compiletime/struct_unit.stderr new file mode 100644 index 0000000000..2497827a4e --- /dev/null +++ b/module/core/derive_tools/tests/inc/index_mut/compiletime/struct_unit.stderr @@ -0,0 +1,7 @@ +error: proc-macro derive panicked + --> tests/inc/index_mut/compiletime/struct_unit.rs:3:12 + | +3 | #[ derive( IndexMut ) ] + | ^^^^^^^^ + | + = help: message: not implemented: IndexMut not implemented for Unit diff --git a/module/core/derive_tools/tests/inc/index_mut/only_test/struct_multiple_named.rs b/module/core/derive_tools/tests/inc/index_mut/only_test/struct_multiple_named.rs new file mode 100644 index 0000000000..0d79398809 --- /dev/null +++ b/module/core/derive_tools/tests/inc/index_mut/only_test/struct_multiple_named.rs @@ -0,0 +1,20 @@ +#[ test ] +fn index_mut() +{ + let mut x = StructMultipleNamed + { + a : vec![ 4, 17 ], + b : vec![ 33, 55 ] + }; + + x[ 0 ] = 5; + x[ 1 ] = 18; + let v = vec![ 5, 18 ]; + + let exp = ( v[ 0 ], v[ 1 ] ); + let got = ( x[ 0 ], x[ 1 ] ); + + assert_eq!( got, exp ); +} + + diff --git a/module/core/derive_tools/tests/inc/index_mut/only_test/struct_multiple_tuple.rs b/module/core/derive_tools/tests/inc/index_mut/only_test/struct_multiple_tuple.rs new file mode 100644 index 0000000000..115e50ad7e --- /dev/null +++ b/module/core/derive_tools/tests/inc/index_mut/only_test/struct_multiple_tuple.rs @@ -0,0 +1,14 @@ +#[ test ] +fn index_mut() +{ + let mut x = StructMultipleTuple( false, vec![ 2, 44, 81 ] ); + + x[ 0 ] = 18; + x[ 1 ] = 99; + + let exp = ( 18, 99 ); + let got = ( x[ 0 ], x[ 1 ] ); + + assert_eq!( got, exp ); +} + diff --git a/module/core/derive_tools/tests/inc/index_mut/only_test/struct_named.rs b/module/core/derive_tools/tests/inc/index_mut/only_test/struct_named.rs new file mode 100644 index 0000000000..c2e20f82fe --- /dev/null +++ b/module/core/derive_tools/tests/inc/index_mut/only_test/struct_named.rs @@ -0,0 +1,18 @@ +#[ test ] +fn index_mut() +{ + let mut x = StructNamed + { + a : vec![ 4, 17 ] + }; + + x[ 0 ] = 5; + x[ 1 ] = 18; + let v = vec![ 5, 18 ]; + + let exp = ( v[ 0 ], v[ 1 ] ); + let got = ( x[ 0 ], x[ 1 ] ); + + assert_eq!( got, exp ); +} + diff --git a/module/core/derive_tools/tests/inc/index_mut/only_test/struct_tuple.rs b/module/core/derive_tools/tests/inc/index_mut/only_test/struct_tuple.rs new file mode 100644 index 0000000000..e120e9ffbe --- /dev/null +++ b/module/core/derive_tools/tests/inc/index_mut/only_test/struct_tuple.rs @@ -0,0 +1,14 @@ +#[ test ] +fn index_mut() +{ + let mut x = StructTuple( vec![ 2, 44, 81 ] ); + + x[ 0 ] = 18; + x[ 1 ] = 99; + + let exp = ( 18, 99 ); + let got = ( x[ 0 ], x[ 1 ] ); + + assert_eq!( got, exp ); +} + diff --git a/module/core/derive_tools/tests/inc/index_mut/struct_collisions.rs b/module/core/derive_tools/tests/inc/index_mut/struct_collisions.rs new file mode 100644 index 0000000000..26349c9cf5 --- /dev/null +++ b/module/core/derive_tools/tests/inc/index_mut/struct_collisions.rs @@ -0,0 +1,22 @@ + +#![ allow( non_snake_case ) ] +#![ allow( unused_imports ) ] +use super::*; + +pub mod core {} +pub mod std {} +pub mod marker {} + +pub mod a {} +pub mod b {} + +#[ derive( the_module::IndexMut ) ] +#[ allow( dead_code ) ] +struct StructMultipleNamed< T > +{ + a : Vec< T >, + #[ index ] + b : Vec< T >, +} + +include!( "./only_test/struct_multiple_named.rs" ); diff --git a/module/core/derive_tools/tests/inc/index_mut/struct_multiple_named_field.rs b/module/core/derive_tools/tests/inc/index_mut/struct_multiple_named_field.rs new file mode 100644 index 0000000000..4ba00b6f89 --- /dev/null +++ b/module/core/derive_tools/tests/inc/index_mut/struct_multiple_named_field.rs @@ -0,0 +1,14 @@ +#![ allow( dead_code ) ] +#[ allow( unused_imports ) ] +use super::*; + +#[ derive( the_module::IndexMut ) ] +struct StructMultipleNamed< T > +{ + a : Vec< T >, + #[ index ] + b : Vec< T >, +} + +include!( "./only_test/struct_multiple_named.rs" ); + diff --git a/module/core/derive_tools/tests/inc/index_mut/struct_multiple_named_item.rs b/module/core/derive_tools/tests/inc/index_mut/struct_multiple_named_item.rs new file mode 100644 index 0000000000..4620c59687 --- /dev/null +++ b/module/core/derive_tools/tests/inc/index_mut/struct_multiple_named_item.rs @@ -0,0 +1,15 @@ +#![ allow( dead_code ) ] +#[ allow( unused_imports ) ] +use super::*; + +#[ derive( the_module::IndexMut ) ] +#[ index( name = b ) ] +struct StructMultipleNamed< T > +{ + a : Vec< T >, + b : Vec< T >, +} + +include!( "./only_test/struct_multiple_named.rs" ); + + diff --git a/module/core/derive_tools/tests/inc/index_mut/struct_multiple_named_manual.rs b/module/core/derive_tools/tests/inc/index_mut/struct_multiple_named_manual.rs new file mode 100644 index 0000000000..1d8830a6da --- /dev/null +++ b/module/core/derive_tools/tests/inc/index_mut/struct_multiple_named_manual.rs @@ -0,0 +1,30 @@ +use core::ops::{ Index, IndexMut }; + +#[ allow( dead_code ) ] +struct StructMultipleNamed< T > +{ + a : Vec< T >, + b : Vec< T >, +} + +impl< T > Index< usize > for StructMultipleNamed< T > +{ + type Output = T; + + fn index( &self, index : usize ) -> &Self::Output + { + &self.b[ index ] + } +} + +impl< T > IndexMut< usize > for StructMultipleNamed< T > +{ + fn index_mut( &mut self, index : usize ) -> &mut Self::Output + { + &mut self.b[ index ] + } +} + + +include!( "./only_test/struct_multiple_named.rs" ); + diff --git a/module/core/derive_tools/tests/inc/index_mut/struct_multiple_tuple.rs b/module/core/derive_tools/tests/inc/index_mut/struct_multiple_tuple.rs new file mode 100644 index 0000000000..41c9a21877 --- /dev/null +++ b/module/core/derive_tools/tests/inc/index_mut/struct_multiple_tuple.rs @@ -0,0 +1,15 @@ +#![ allow( dead_code ) ] +#[ allow( unused_imports ) ] +use super::*; + + +#[ derive( the_module::IndexMut ) ] +struct StructMultipleTuple< T > +( + bool, + #[ index ] + Vec< T > +); + +include!( "./only_test/struct_multiple_tuple.rs" ); + diff --git a/module/core/derive_tools/tests/inc/index_mut/struct_multiple_tuple_manual.rs b/module/core/derive_tools/tests/inc/index_mut/struct_multiple_tuple_manual.rs new file mode 100644 index 0000000000..66ffeb906f --- /dev/null +++ b/module/core/derive_tools/tests/inc/index_mut/struct_multiple_tuple_manual.rs @@ -0,0 +1,27 @@ +use core::ops::{ Index, IndexMut }; + +#[ allow( dead_code ) ] +struct StructMultipleTuple< T >( bool, Vec< T > ); + +impl< T > Index< usize > for StructMultipleTuple< T > +{ + type Output = T; + + fn index( &self, index : usize ) -> &Self::Output + { + &self.1[ index ] + } +} + +impl< T > IndexMut< usize > for StructMultipleTuple< T > +{ + fn index_mut( &mut self, index : usize ) -> &mut Self::Output + { + &mut self.1[ index ] + } +} + + +include!( "./only_test/struct_multiple_tuple.rs" ); + + diff --git a/module/core/derive_tools/tests/inc/index_mut/struct_named.rs b/module/core/derive_tools/tests/inc/index_mut/struct_named.rs new file mode 100644 index 0000000000..162547488a --- /dev/null +++ b/module/core/derive_tools/tests/inc/index_mut/struct_named.rs @@ -0,0 +1,12 @@ +#![ allow( dead_code ) ] +#[ allow( unused_imports ) ] +use super::*; + +#[ derive( the_module::IndexMut ) ] +struct StructNamed< T > +{ + #[ index ] + a : Vec< T >, +} + +include!( "./only_test/struct_named.rs" ); diff --git a/module/core/derive_tools/tests/inc/index_mut/struct_named_manual.rs b/module/core/derive_tools/tests/inc/index_mut/struct_named_manual.rs new file mode 100644 index 0000000000..2c8c3bebc4 --- /dev/null +++ b/module/core/derive_tools/tests/inc/index_mut/struct_named_manual.rs @@ -0,0 +1,28 @@ +use core::ops::{ Index, IndexMut }; + +#[ allow( dead_code ) ] +struct StructNamed< T > +{ + a : Vec< T > +} + +impl< T > Index< usize > for StructNamed< T > +{ + type Output = T; + + fn index( &self, index : usize ) -> &Self::Output + { + &self.a[ index ] + } +} + +impl< T > IndexMut< usize > for StructNamed< T > +{ + fn index_mut( &mut self, index : usize ) -> &mut Self::Output + { + &mut self.a[ index ] + } +} + + +include!( "./only_test/struct_named.rs" ); diff --git a/module/core/derive_tools/tests/inc/index_mut/struct_tuple.rs b/module/core/derive_tools/tests/inc/index_mut/struct_tuple.rs new file mode 100644 index 0000000000..f252344d58 --- /dev/null +++ b/module/core/derive_tools/tests/inc/index_mut/struct_tuple.rs @@ -0,0 +1,12 @@ +#![ allow( dead_code ) ] +#[ allow( unused_imports ) ] +use super::*; + +#[ derive( the_module::IndexMut ) ] +struct StructTuple< T > +( + #[ index ] + Vec< T > +); + +include!( "./only_test/struct_tuple.rs" ); diff --git a/module/core/derive_tools/tests/inc/index_mut/struct_tuple_manual.rs b/module/core/derive_tools/tests/inc/index_mut/struct_tuple_manual.rs new file mode 100644 index 0000000000..be299f90c6 --- /dev/null +++ b/module/core/derive_tools/tests/inc/index_mut/struct_tuple_manual.rs @@ -0,0 +1,26 @@ +use core::ops::{ Index, IndexMut }; + +#[ allow( dead_code ) ] +struct StructTuple< T >( Vec< T > ); + +impl< T > Index< usize > for StructTuple< T > +{ + type Output = T; + + fn index( &self, index : usize ) -> &Self::Output + { + &self.0[ index ] + } +} + +impl< T > IndexMut< usize > for StructTuple< T > +{ + fn index_mut( &mut self, index : usize ) -> &mut Self::Output + { + &mut self.0[ index ] + } +} + + +include!( "./only_test/struct_tuple.rs" ); + diff --git a/module/core/derive_tools/tests/inc/mod.rs b/module/core/derive_tools/tests/inc/mod.rs index feff00a160..6f46e324f5 100644 --- a/module/core/derive_tools/tests/inc/mod.rs +++ b/module/core/derive_tools/tests/inc/mod.rs @@ -25,6 +25,7 @@ mod all_manual_test; feature = "derive_deref_mut", feature = "derive_from", feature = "derive_index", + feature = "derive_index_mut", feature = "derive_inner_from", feature = "derive_phantom" ) @@ -304,7 +305,7 @@ mod index_tests #[ allow( unused_imports ) ] use super::*; - mod struct_named; + mod struct_named; mod struct_multiple_named; mod struct_named_manual; mod struct_multiple_named_manual; @@ -330,3 +331,39 @@ mod index_tests } } } + +#[ cfg( feature = "derive_index_mut" ) ] +#[ path = "index_mut" ] +mod index_mut_tests +{ + #[ allow( unused_imports ) ] + use super::*; + mod struct_named; + mod struct_multiple_named_field; + mod struct_multiple_named_item; + mod struct_named_manual; + mod struct_multiple_named_manual; + mod struct_tuple; + mod struct_multiple_tuple; + mod struct_tuple_manual; + mod struct_multiple_tuple_manual; + mod struct_collisions; + + only_for_terminal_module! + { + #[ test_tools::nightly ] + #[ test ] + fn index_mut_trybuild() + { + + println!( "current_dir : {:?}", std::env::current_dir().unwrap() ); + let t = test_tools::compiletime::TestCases::new(); + + t.compile_fail( "tests/inc/index_mut/compiletime/struct.rs" ); + t.compile_fail( "tests/inc/index_mut/compiletime/struct_unit.rs" ); + t.compile_fail( "tests/inc/index_mut/compiletime/struct_named_empty.rs" ); + t.compile_fail( "tests/inc/index_mut/compiletime/enum.rs" ); + } + } +} + diff --git a/module/core/derive_tools_meta/Cargo.toml b/module/core/derive_tools_meta/Cargo.toml index c403ea99b2..b900cac761 100644 --- a/module/core/derive_tools_meta/Cargo.toml +++ b/module/core/derive_tools_meta/Cargo.toml @@ -35,6 +35,7 @@ default = [ "derive_from", "derive_new", "derive_index", + "derive_index_mut", "derive_inner_from", "derive_as_ref", "derive_as_mut", @@ -48,6 +49,7 @@ full = [ "derive_from", "derive_new", "derive_index", + "derive_index_mut", "derive_inner_from", "derive_as_ref", "derive_as_mut", @@ -63,6 +65,7 @@ derive_deref_mut = [] derive_from = [] derive_new = [] derive_index = [] +derive_index_mut = [] derive_inner_from = [] derive_variadic_from = [ "iter_tools/iter_ext" ] derive_phantom = [] diff --git a/module/core/derive_tools_meta/src/derive.rs b/module/core/derive_tools_meta/src/derive.rs index b8e4e131cd..9954ad4443 100644 --- a/module/core/derive_tools_meta/src/derive.rs +++ b/module/core/derive_tools_meta/src/derive.rs @@ -20,6 +20,8 @@ pub mod deref_mut; pub mod from; #[ cfg( feature = "derive_index" ) ] pub mod index; +#[ cfg( feature = "derive_index_mut" ) ] +pub mod index_mut; #[ cfg( feature = "derive_inner_from" ) ] pub mod inner_from; #[ cfg( feature = "derive_new" ) ] diff --git a/module/core/derive_tools_meta/src/derive/index_mut.rs b/module/core/derive_tools_meta/src/derive/index_mut.rs new file mode 100644 index 0000000000..fc72715eea --- /dev/null +++ b/module/core/derive_tools_meta/src/derive/index_mut.rs @@ -0,0 +1,362 @@ +use super::*; +use macro_tools:: +{ + attr, + diag, + generic_params, + struct_like::StructLike, + Result +}; + +#[ path = "index/item_attributes.rs" ] +mod item_attributes; +use item_attributes::*; +#[ path = "index/field_attributes.rs" ] +mod field_attributes; +use field_attributes::*; + + +pub fn index_mut( input : proc_macro::TokenStream ) -> Result< proc_macro2::TokenStream > +{ + let original_input = input.clone(); + let parsed = syn::parse::< StructLike >( input )?; + let has_debug = attr::has_debug( parsed.attrs().iter() )?; + let item_name = &parsed.ident(); + + let item_attrs = ItemAttributes::from_attrs( parsed.attrs().iter() )?; + + let ( _generics_with_defaults, generics_impl, generics_ty, generics_where ) + = generic_params::decompose( &parsed.generics() ); + + let result = match parsed + { + StructLike::Struct( ref item ) => + generate_struct + ( + item_name, + &item_attrs, + &generics_impl, + &generics_ty, + &generics_where, + &item.fields, + + ), + StructLike::Enum( _ ) => + unimplemented!( "IndexMut not implemented for Enum" ), + StructLike::Unit( _ ) => + unimplemented!( "IndexMut not implemented for Unit" ), + }?; + + if has_debug + { + let about = format!( "derive : Not\nstructure : {item_name}" ); + diag::report_print( about, &original_input, &result ); + } + + Ok( result ) +} + +/// An aggregator function to generate `IndexMut` implementation for tuple and named structs +fn generate_struct +( + 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 >, + fields : &syn::Fields, +) +-> Result< proc_macro2::TokenStream > +{ + + match fields + { + syn::Fields::Named( fields ) => + generate_struct_named_fields + ( + item_name, + &item_attrs, + generics_impl, + generics_ty, + generics_where, + fields + ), + + syn::Fields::Unnamed( fields ) => + generate_struct_tuple_fields + ( + item_name, + generics_impl, + generics_ty, + generics_where, + fields + ), + + syn::Fields::Unit => + unimplemented!( "IndexMut not implemented for Unit" ), + } +} + + +fn generate_struct_named_fields +( + 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 >, + fields : &syn::FieldsNamed, +) +-> Result< proc_macro2::TokenStream > +{ + + let fields = fields.named.clone(); + let attr_name = &item_attrs.index.name.clone().internal(); + + let field_attrs: Vec< &syn::Field > = fields + .iter() + .filter + ( + | field | + { + FieldAttributes::from_attrs( field.attrs.iter() ).map_or + ( + false, + | attrs | attrs.index.value( false ) + ) + } + ) + .collect(); + + let generate = | is_mut : bool | + -> Result< proc_macro2::TokenStream > + { + if let Some( attr_name ) = attr_name + { + Ok + ( + if is_mut + { + qt! + { + &mut self.#attr_name[ index ] + } + } + else + { + qt! + { + &self.#attr_name[ index ] + } + } + ) + } + else + { + match field_attrs.len() + { + 0 | 1 => + { + let field_name = + match field_attrs + .first() + .cloned() + .or_else + ( + || fields.first() + ) + { + Some( field ) => + field.ident.as_ref().unwrap(), + None => + unimplemented!( "IndexMut not implemented for Unit" ), + }; + + Ok + ( + if is_mut + { + qt! + { + &mut self.#field_name[ index ] + } + } + else + { + qt! + { + &self.#field_name[ index ] + } + } + ) + } + _ => + Err + ( + syn::Error::new_spanned + ( + &fields, + "Only one field can include #[ index ] derive macro", + ) + ), + } + } + }; + + + let generated_index = generate( false )?; + let generated_index_mut = generate( true )?; + + Ok + ( + qt! + { + #[ automatically_derived ] + impl< #generics_impl > ::core::ops::Index< usize > for #item_name< #generics_ty > + where + #generics_where + { + type Output = T; + #[ inline( always ) ] + fn index( &self, index : usize ) -> &Self::Output + { + #generated_index + } + } + + #[ automatically_derived ] + impl< #generics_impl > ::core::ops::IndexMut< usize > for #item_name< #generics_ty > + where + #generics_where + { + #[ inline( always ) ] + fn index_mut( &mut self, index : usize ) -> &mut Self::Output + { + #generated_index_mut + } + } + } + ) +} + +fn generate_struct_tuple_fields +( + 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 >, + fields : &syn::FieldsUnnamed, +) +-> Result< proc_macro2::TokenStream > +{ + let fields = fields.unnamed.clone(); + let non_empty_attrs : Vec< &syn::Field > = fields + .iter() + .filter( | field | !field.attrs.is_empty() ) + .collect(); + + + let generate = | is_mut : bool | + -> Result< proc_macro2::TokenStream > + { + match non_empty_attrs.len() + { + 0 => + { + Ok + ( + if is_mut + { + qt! + { + &mut self.0[ index ] + } + } + else + { + qt! + { + &self.0[ index ] + } + } + ) + }, + 1 => fields + .iter() + .enumerate() + .map + ( + | ( i, field ) | + { + let i = syn::Index::from( i ); + if !field.attrs.is_empty() + { + Ok + ( + if is_mut + { + qt!{&mut self.#i[ index ]} + } + else + { + qt!{&self.#i[ index ] } + } + ) + } + else + { + Ok + ( + qt!{ } + ) + } + } + ).collect(), + _ => + Err + ( + syn::Error::new_spanned + ( + &fields, + "Only one field can include #[ index ] derive macro" + ) + ), + } + }; + + + + let generated = generate( false )?; + let generated_mut = generate( true )?; + + Ok + ( + qt! + { + #[ automatically_derived ] + impl< #generics_impl > ::core::ops::Index< usize > for #item_name< #generics_ty > + where + #generics_where + { + type Output = T; + #[ inline( always ) ] + fn index( &self, index : usize ) -> &Self::Output + { + #generated + } + } + + #[ automatically_derived ] + impl< #generics_impl > ::core::ops::IndexMut< usize > for #item_name< #generics_ty > + where + #generics_where + { + #[ inline( always ) ] + fn index_mut( &mut self, index : usize ) -> &mut Self::Output + { + #generated_mut + } + } + } + ) +} diff --git a/module/core/derive_tools_meta/src/lib.rs b/module/core/derive_tools_meta/src/lib.rs index 05aaebac0a..0bf7a79669 100644 --- a/module/core/derive_tools_meta/src/lib.rs +++ b/module/core/derive_tools_meta/src/lib.rs @@ -14,6 +14,7 @@ feature = "derive_deref_mut", feature = "derive_from", feature = "derive_index", + feature = "derive_index_mut", feature = "derive_inner_from", feature = "derive_variadic_from", feature = "derive_phantom" @@ -31,6 +32,7 @@ mod derive; // feature = "derive_deref_mut", // feature = "derive_from", // feature = "derive_index", +// feature = "derive_index_mut", // feature = "derive_inner_from", // feature = "derive_variadic_from", // feature = "derive_phantom" @@ -630,3 +632,74 @@ pub fn derive_index( input : proc_macro::TokenStream ) -> proc_macro::TokenStrea Err( err ) => err.to_compile_error().into(), } } + +/// +/// Provides an automatic [IndexMut](core::ops::IndexMut) trait implementation when-ever it's possible. +/// +/// This macro simplifies the indexing syntax of struct type. +/// +/// ## Example Usage +// +/// Instead of manually implementing `IndexMut< T >` for `IsTransparent`: +/// +/// ```rust +/// use core::ops::{ Index, IndexMut }; +/// pub struct IsTransparent< T > +/// { +/// a : Vec< T >, +/// } +/// +/// impl< T > Index< usize > for IsTransparent< T > +/// { +/// type Output = T; +/// +/// #[ inline( always ) ] +/// fn index( &self, index : usize ) -> &Self::Output +/// { +/// &self.a[ index ] +/// } +/// } +/// +/// impl< T > IndexMut< usize > for IsTransparent< T > +/// { +/// fn index_mut( &mut self, index : usize ) -> &mut Self::Output +/// { +/// &mut self.a[ index ] +/// } +/// } +/// ``` +/// +/// Use `#[ index ]` on field or `#[ index( name = field_name )]` on named items to automatically generate the implementation: +/// +/// ```rust +/// use derive_tools_meta::*; +/// #[derive( IndexMut )] +/// pub struct IsTransparent< T > +/// { +/// #[ index ] +/// a : Vec< T > +/// }; +/// ``` +/// + +#[ cfg( feature = "enabled" ) ] +#[ cfg( feature = "derive_index_mut" ) ] +#[ proc_macro_derive +( + IndexMut, + attributes + ( + debug, // item + index, // field + ) +)] +pub fn derive_index_mut( input : proc_macro::TokenStream ) -> proc_macro::TokenStream +{ + let result = derive::index_mut::index_mut( input ); + match result + { + Ok( stream ) => stream.into(), + Err( err ) => err.to_compile_error().into(), + } +} +