From 35a85bf91f42bcb197cb7bd4fb47e08db1bb136f Mon Sep 17 00:00:00 2001 From: Inkvisto Date: Wed, 10 Jul 2024 17:11:40 +0300 Subject: [PATCH 1/7] macros skeleton --- module/core/derive_tools/Cargo.toml | 3 +- module/core/derive_tools/build.rs | 2 + module/core/derive_tools/src/lib.rs | 2 - .../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 ++ .../index_mut/struct_multiple_named_manual.rs | 30 +++ .../index_mut/struct_multiple_tuple_manual.rs | 27 ++ .../inc/index_mut/struct_named_manual.rs | 28 +++ .../inc/index_mut/struct_tuple_manual.rs | 26 ++ module/core/derive_tools/tests/inc/mod.rs | 20 +- .../src/derive/index_mut/field_attributes.rs | 98 ++++++++ .../src/derive/index_mut/item_attributes.rs | 233 ++++++++++++++++++ 14 files changed, 531 insertions(+), 4 deletions(-) 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_multiple_named_manual.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_manual.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/field_attributes.rs create mode 100644 module/core/derive_tools_meta/src/derive/index_mut/item_attributes.rs diff --git a/module/core/derive_tools/Cargo.toml b/module/core/derive_tools/Cargo.toml index 777d5f745f..53f3a58255 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/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..f3e4a0fa19 --- /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_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_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_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_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..838a18d3bc 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,20 @@ 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; + 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; +} + diff --git a/module/core/derive_tools_meta/src/derive/index_mut/field_attributes.rs b/module/core/derive_tools_meta/src/derive/index_mut/field_attributes.rs new file mode 100644 index 0000000000..260b6edf4a --- /dev/null +++ b/module/core/derive_tools_meta/src/derive/index_mut/field_attributes.rs @@ -0,0 +1,98 @@ +use super::*; +use macro_tools:: +{ + ct, + Result, + AttributePropertyComponent, + AttributePropertyOptionalSingletone, + Assign, +}; + +/// +/// Attributes of a field / variant +/// + +/// Represents the attributes of a struct. Aggregates all its attributes. +#[ derive( Debug, Default ) ] +pub struct FieldAttributes +{ + /// Specifies whether we should generate IndexMut implementation for the field. + pub index_mut : AttributePropertyIndexMut, +} + +impl FieldAttributes +{ + /// 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 = ct::concatcp! + ( + "Known attributes are : ", + ", ", AttributePropertyIndexMut::KEYWORD, + ".", + ); + syn_err! + ( + attr, + "Expects an attribute of format '#[ attribute ]'\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() + { + AttributePropertyIndexMut::KEYWORD => result.assign( AttributePropertyIndexMut::from( true ) ), + _ => {}, + // _ => return Err( error( attr ) ), + } + } + + Ok( result ) + } +} + +impl< IntoT > Assign< AttributePropertyIndexMut, IntoT > for FieldAttributes +where + IntoT : Into< AttributePropertyIndexMut >, +{ + #[ inline( always ) ] + fn assign( &mut self, component : IntoT ) + { + self.index_mut.assign( component.into() ); + } +} + + +// == Attribute properties + +/// Marker type for attribute property to indicate whether a index_mut code should be generated. +/// Defaults to `false`, meaning no index_mut code is generated unless explicitly requested. +#[ derive( Debug, Default, Clone, Copy ) ] +pub struct AttributePropertyIndexMutMarker; + +impl AttributePropertyComponent for AttributePropertyIndexMutMarker +{ + const KEYWORD : & 'static str = "index_mut"; +} + +/// Indicates whether a index_mut code should be generated. +/// Defaults to `false`, meaning no index_mut code is generated unless explicitly requested. +pub type AttributePropertyIndexMut = AttributePropertyOptionalSingletone< AttributePropertyIndexMutMarker >; + +// == + + + diff --git a/module/core/derive_tools_meta/src/derive/index_mut/item_attributes.rs b/module/core/derive_tools_meta/src/derive/index_mut/item_attributes.rs new file mode 100644 index 0000000000..81209d8b1d --- /dev/null +++ b/module/core/derive_tools_meta/src/derive/index_mut/item_attributes.rs @@ -0,0 +1,233 @@ +use super::*; +use macro_tools:: +{ + ct, + Result, + AttributeComponent, + AttributePropertyComponent, + AttributePropertyOptionalSyn, + AttributePropertyOptionalSingletone, +}; + +/// Represents the attributes of a struct. Aggregates all its attributes. +#[ derive( Debug, Default ) ] +pub struct ItemAttributes +{ + /// Attribute for customizing generated code. + pub index_mut : ItemAttributeIndexMut, + /// Specifies whether to provide a generated code as a hint. + /// Defaults to `false`, which means no code is printed unless explicitly requested. + pub debug : AttributePropertyDebug, +} + +#[ derive( Debug, Default ) ] +pub struct ItemAttributeIndexMut +{ + /// Specifies what specific named field must implement IndexMut. + pub name : AttributePropertyName, +} + +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 = ct::concatcp! + ( + "Known attributes are: ", + "debug", + ", ", ItemAttributeIndexMut::KEYWORD, + "." + ); + syn_err! + ( + attr, + "Expects an attribute of format '#[ attribute ]'\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() + { + ItemAttributeIndexMut::KEYWORD => result.assign( ItemAttributeIndexMut::from_meta( attr )? ), + "debug" => {}, + _ => {}, + // _ => return Err( error( attr ) ), + } + } + + Ok( result ) + } +} + +impl AttributeComponent for ItemAttributeIndexMut +{ + const KEYWORD : &'static str = "index_mut"; + + fn from_meta( attr : &syn::Attribute ) -> Result< Self > + { + match attr.meta + { + syn::Meta::List( ref meta_list ) => + { + return syn::parse2::< ItemAttributeIndexMut >( 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< ItemAttributeIndexMut, IntoT > for ItemAttributes +where + IntoT : Into< ItemAttributeIndexMut >, +{ + #[ inline( always ) ] + fn assign( &mut self, component : IntoT ) + { + self.index_mut.assign( component.into() ); + } +} + + + +impl< IntoT > Assign< AttributePropertyDebug, IntoT > for ItemAttributes +where + IntoT : Into< AttributePropertyDebug >, +{ + #[ inline( always ) ] + fn assign( &mut self, component : IntoT ) + { + self.debug = component.into(); + } +} + + +impl< IntoT > Assign< ItemAttributeIndexMut, IntoT > for ItemAttributeIndexMut +where + IntoT : Into< ItemAttributeIndexMut >, +{ + #[ inline( always ) ] + fn assign( &mut self, component : IntoT ) + { + let component = component.into(); + self.name.assign( component.name ); + } +} + +impl< IntoT > Assign< AttributePropertyName, IntoT > for ItemAttributeIndexMut +where + IntoT : Into< AttributePropertyName >, +{ + #[ inline( always ) ] + fn assign( &mut self, component : IntoT ) + { + self.name = component.into(); + } +} + + +impl syn::parse::Parse for ItemAttributeIndexMut +{ + fn parse( input : syn::parse::ParseStream< '_ > ) -> syn::Result< Self > + { + let mut result = Self::default(); + + let error = | ident : &syn::Ident | -> syn::Error + { + let known = ct::concatcp! + ( + "Known entries of attribute ", ItemAttributeIndexMut::KEYWORD, " are : ", + AttributePropertyName::KEYWORD, + ".", + ); + 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() + { + AttributePropertyName::KEYWORD => result.assign( AttributePropertyName::parse( input )? ), + _ => 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 of optional identifier that names the setter. It is parsed from inputs +/// like `name = field_name`. +#[ derive( Debug, Default, Clone, Copy ) ] +pub struct NameMarker; + +impl AttributePropertyComponent for NameMarker +{ + const KEYWORD : &'static str = "name"; +} + +/// An optional identifier that names the setter. It is parsed from inputs +/// like `name = field_name`. +pub type AttributePropertyName = AttributePropertyOptionalSyn< syn::Ident, NameMarker >; + +// = + +/// 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 >; + +// == From 2e680fe343139dc469de97e5ca3d27b4d6f3b587 Mon Sep 17 00:00:00 2001 From: Inkvisto Date: Thu, 11 Jul 2024 13:12:03 +0300 Subject: [PATCH 2/7] fut: index_mut macro implementation, add tests --- .../tests/inc/index/struct_named.rs | 2 +- .../inc/index_mut/struct_multiple_named.rs | 15 + .../inc/index_mut/struct_multiple_tuple.rs | 16 + .../tests/inc/index_mut/struct_named.rs | 13 + .../tests/inc/index_mut/struct_tuple.rs | 13 + module/core/derive_tools/tests/inc/mod.rs | 8 +- 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 | 290 ++++++++++++++++++ module/core/derive_tools_meta/src/lib.rs | 74 +++++ 10 files changed, 431 insertions(+), 5 deletions(-) create mode 100644 module/core/derive_tools/tests/inc/index_mut/struct_multiple_named.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_named.rs create mode 100644 module/core/derive_tools/tests/inc/index_mut/struct_tuple.rs create mode 100644 module/core/derive_tools_meta/src/derive/index_mut.rs diff --git a/module/core/derive_tools/tests/inc/index/struct_named.rs b/module/core/derive_tools/tests/inc/index/struct_named.rs index ca5b884595..d44c21837b 100644 --- a/module/core/derive_tools/tests/inc/index/struct_named.rs +++ b/module/core/derive_tools/tests/inc/index/struct_named.rs @@ -5,7 +5,7 @@ use super::*; #[ derive( the_module::Index ) ] struct StructNamed< T > { - #[ index ] + // #[ index ] a : Vec< T >, } diff --git a/module/core/derive_tools/tests/inc/index_mut/struct_multiple_named.rs b/module/core/derive_tools/tests/inc/index_mut/struct_multiple_named.rs new file mode 100644 index 0000000000..85292d3a83 --- /dev/null +++ b/module/core/derive_tools/tests/inc/index_mut/struct_multiple_named.rs @@ -0,0 +1,15 @@ +#![ allow( dead_code ) ] +#[ allow( unused_imports ) ] +use super::*; + +#[ derive( the_module::Index, the_module::IndexMut ) ] +#[ index_mut( name = b) ] +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_tuple.rs b/module/core/derive_tools/tests/inc/index_mut/struct_multiple_tuple.rs new file mode 100644 index 0000000000..1e9d3b07e8 --- /dev/null +++ b/module/core/derive_tools/tests/inc/index_mut/struct_multiple_tuple.rs @@ -0,0 +1,16 @@ +#![ allow( dead_code ) ] +#[ allow( unused_imports ) ] +use super::*; + + +#[ derive( the_module::Index, the_module::IndexMut ) ] +struct StructMultipleTuple< T > +( + bool, + #[ index ] + #[ index_mut ] + Vec< T > +); + +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..ee3ba77970 --- /dev/null +++ b/module/core/derive_tools/tests/inc/index_mut/struct_named.rs @@ -0,0 +1,13 @@ +#![ allow( dead_code ) ] +#[ allow( unused_imports ) ] +use super::*; + +#[ derive( the_module::Index, the_module::IndexMut ) ] +struct StructNamed< T > +{ + #[ index ] + #[ index_mut ] + a : Vec< T >, +} + +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..3f6fbf13d0 --- /dev/null +++ b/module/core/derive_tools/tests/inc/index_mut/struct_tuple.rs @@ -0,0 +1,13 @@ +#![ allow( dead_code ) ] +#[ allow( unused_imports ) ] +use super::*; + +#[ derive( the_module::Index, the_module::IndexMut ) ] +struct StructTuple< T > +( + #[ index ] + #[ index_mut ] + Vec< T > +); + +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 838a18d3bc..89d12692e2 100644 --- a/module/core/derive_tools/tests/inc/mod.rs +++ b/module/core/derive_tools/tests/inc/mod.rs @@ -338,12 +338,12 @@ mod index_mut_tests { #[ allow( unused_imports ) ] use super::*; - // mod struct_named; - // mod struct_multiple_named; + mod struct_named; + mod struct_multiple_named; mod struct_named_manual; mod struct_multiple_named_manual; - // mod struct_tuple; - // mod struct_multiple_tuple; + mod struct_tuple; + mod struct_multiple_tuple; mod struct_tuple_manual; mod struct_multiple_tuple_manual; } diff --git a/module/core/derive_tools_meta/Cargo.toml b/module/core/derive_tools_meta/Cargo.toml index f16ebfdd62..b7c09ec8aa 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..5c0b17dba5 --- /dev/null +++ b/module/core/derive_tools_meta/src/derive/index_mut.rs @@ -0,0 +1,290 @@ +use super::*; +use macro_tools:: +{ + attr, + diag, + generic_params, + struct_like::StructLike, + Result +}; + +#[ path = "index_mut/item_attributes.rs" ] +mod item_attributes; +use item_attributes::*; +#[ path = "index_mut/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 > +{ + + +// dbg!(&item_attrs.index_mut.name.clone().internal()); + // if item_attrs.index_mut.name.internal( ) + // { + // return Ok( qt!{} ) + // } + + let fields = fields.named.clone(); + let attr_name = &item_attrs.index_mut.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_mut.value( false ) + ) + } + ) + .collect(); + + + let generated = if let Some(attr_name) = attr_name + { + qt! + { + &mut self.#attr_name[ index ] + } + } + else + { + match field_attrs.len() + { + 0 => + { + return Err + ( + syn::Error::new_spanned + ( + &fields, + "No attributes specified. You must to specify #[ index_mut ] for fields or name for #[ index_mut ( name = field_name ) ] for item derive macro" + ) + ); + }, + 1 => field_attrs.iter().map + ( + | field | + { + let field_name = &field.ident; + + if !field.attrs.is_empty() + { + qt! + { + &mut self.#field_name[ index ] + } + } + else + { + qt!{ } + } + } + ).collect(), + _ => + { + return Err + ( + syn::Error::new_spanned + ( + &fields, + "Only one field can include #[ index_mut ] derive macro" + ) + ); + } + } + }; + + Ok + ( + qt! + { + #[ 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 + } + } + } + ) +} + +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 generated = match non_empty_attrs.len() + { + 0 => + { + return Err + ( + syn::Error::new_spanned + ( + &fields, + "No attributes specified. You must to specify #[ index_mut ] for fields or name for #[ index_mut ( name = field_name ) ] for item derive macro" + ) + ); + }, + 1 => fields.iter().enumerate().map + ( + | ( i, field ) | + { + let i = syn::Index::from( i ); + if !field.attrs.is_empty() + { + qt! + { + &mut self.#i[ index ] + } + } + else + { + qt!{ } + } + } + ), + _ => + { + return Err + ( + syn::Error::new_spanned + ( + &fields, + "Only one field can include #[ index_mut ] derive macro" + ) + ); + } + }; + + Ok + ( + qt! + { + #[ 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 )* + } + } + } + ) +} diff --git a/module/core/derive_tools_meta/src/lib.rs b/module/core/derive_tools_meta/src/lib.rs index 05aaebac0a..31f1ac9a9d 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,75 @@ 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_mut ]` on field or `#[ index_mut( name = field_name )]` on named items to automatically generate the implementation: +/// +/// ```rust +/// use derive_tools_meta::*; +/// #[derive( Index, IndexMut )] +/// pub struct IsTransparent< T > +/// { +/// #[ index ] +/// #[ index_mut ] +/// a : Vec< T > +/// }; +/// ``` +/// + +#[ cfg( feature = "enabled" ) ] +#[ cfg( feature = "derive_index_mut" ) ] +#[ proc_macro_derive +( + IndexMut, + attributes + ( + debug, // item + index_mut, // 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(), + } +} + From d73fc5f6db1fb6084890328aeb66985fddb5e571 Mon Sep 17 00:00:00 2001 From: Inkvisto Date: Thu, 11 Jul 2024 14:04:04 +0300 Subject: [PATCH 3/7] fix: index test --- module/core/derive_tools/tests/inc/index/struct_named.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/core/derive_tools/tests/inc/index/struct_named.rs b/module/core/derive_tools/tests/inc/index/struct_named.rs index d44c21837b..ca5b884595 100644 --- a/module/core/derive_tools/tests/inc/index/struct_named.rs +++ b/module/core/derive_tools/tests/inc/index/struct_named.rs @@ -5,7 +5,7 @@ use super::*; #[ derive( the_module::Index ) ] struct StructNamed< T > { - // #[ index ] + #[ index ] a : Vec< T >, } From ae5b9eca84d005ceff46edcfb953257db9b8e5bd Mon Sep 17 00:00:00 2001 From: Inkvisto Date: Thu, 11 Jul 2024 16:54:27 +0300 Subject: [PATCH 4/7] ref: remove not used comments --- module/core/derive_tools_meta/src/derive/index_mut.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/module/core/derive_tools_meta/src/derive/index_mut.rs b/module/core/derive_tools_meta/src/derive/index_mut.rs index 5c0b17dba5..11b77420a9 100644 --- a/module/core/derive_tools_meta/src/derive/index_mut.rs +++ b/module/core/derive_tools_meta/src/derive/index_mut.rs @@ -110,13 +110,6 @@ fn generate_struct_named_fields -> Result< proc_macro2::TokenStream > { - -// dbg!(&item_attrs.index_mut.name.clone().internal()); - // if item_attrs.index_mut.name.internal( ) - // { - // return Ok( qt!{} ) - // } - let fields = fields.named.clone(); let attr_name = &item_attrs.index_mut.name.clone().internal(); From 906d90f07a2823ec4e3ed3ebc35516fecfa14be0 Mon Sep 17 00:00:00 2001 From: Inkvisto Date: Thu, 11 Jul 2024 20:33:48 +0300 Subject: [PATCH 5/7] ref: index_mut to index --- .../inc/index_mut/struct_multiple_named.rs | 3 +- .../tests/inc/index_mut/struct_named.rs | 3 +- .../derive_tools_meta/src/derive/index_mut.rs | 126 ++++++---- .../src/derive/index_mut/field_attributes.rs | 98 -------- .../src/derive/index_mut/item_attributes.rs | 233 ------------------ module/core/derive_tools_meta/src/lib.rs | 2 +- 6 files changed, 79 insertions(+), 386 deletions(-) delete mode 100644 module/core/derive_tools_meta/src/derive/index_mut/field_attributes.rs delete mode 100644 module/core/derive_tools_meta/src/derive/index_mut/item_attributes.rs diff --git a/module/core/derive_tools/tests/inc/index_mut/struct_multiple_named.rs b/module/core/derive_tools/tests/inc/index_mut/struct_multiple_named.rs index 85292d3a83..4ba00b6f89 100644 --- a/module/core/derive_tools/tests/inc/index_mut/struct_multiple_named.rs +++ b/module/core/derive_tools/tests/inc/index_mut/struct_multiple_named.rs @@ -2,8 +2,7 @@ #[ allow( unused_imports ) ] use super::*; -#[ derive( the_module::Index, the_module::IndexMut ) ] -#[ index_mut( name = b) ] +#[ derive( the_module::IndexMut ) ] struct StructMultipleNamed< T > { a : Vec< T >, 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 index ee3ba77970..162547488a 100644 --- a/module/core/derive_tools/tests/inc/index_mut/struct_named.rs +++ b/module/core/derive_tools/tests/inc/index_mut/struct_named.rs @@ -2,11 +2,10 @@ #[ allow( unused_imports ) ] use super::*; -#[ derive( the_module::Index, the_module::IndexMut ) ] +#[ derive( the_module::IndexMut ) ] struct StructNamed< T > { #[ index ] - #[ index_mut ] a : Vec< T >, } diff --git a/module/core/derive_tools_meta/src/derive/index_mut.rs b/module/core/derive_tools_meta/src/derive/index_mut.rs index 11b77420a9..561b32c3e5 100644 --- a/module/core/derive_tools_meta/src/derive/index_mut.rs +++ b/module/core/derive_tools_meta/src/derive/index_mut.rs @@ -8,10 +8,10 @@ use macro_tools:: Result }; -#[ path = "index_mut/item_attributes.rs" ] +#[ path = "index/item_attributes.rs" ] mod item_attributes; use item_attributes::*; -#[ path = "index_mut/field_attributes.rs" ] +#[ path = "index/field_attributes.rs" ] mod field_attributes; use field_attributes::*; @@ -111,7 +111,7 @@ fn generate_struct_named_fields { let fields = fields.named.clone(); - let attr_name = &item_attrs.index_mut.name.clone().internal(); + let attr_name = &item_attrs.index.name.clone().internal(); let field_attrs: Vec<&syn::Field> = fields .iter() @@ -122,72 +122,98 @@ fn generate_struct_named_fields FieldAttributes::from_attrs( field.attrs.iter() ).map_or ( false, - | attrs | attrs.index_mut.value( false ) + | attrs | attrs.index.value( false ) ) } ) .collect(); - - let generated = if let Some(attr_name) = attr_name - { - qt! - { - &mut self.#attr_name[ index ] - } - } - else + let generate = | is_mut : bool | + -> Result< proc_macro2::TokenStream > { - match field_attrs.len() + if let Some( attr_name ) = attr_name { - 0 => - { - return Err - ( - syn::Error::new_spanned - ( - &fields, - "No attributes specified. You must to specify #[ index_mut ] for fields or name for #[ index_mut ( name = field_name ) ] for item derive macro" - ) - ); - }, - 1 => field_attrs.iter().map + Ok ( - | field | + qt! { - let field_name = &field.ident; - - if !field.attrs.is_empty() - { - qt! + &self.#attr_name[index] + } + ) + } + else + { + match field_attrs.len() + { + 0 | 1 => + { + let field_name = + match field_attrs + .first() + .map(|&field| field) + .or_else + ( + || fields.first() + ) + { + Some( field ) => + field.ident.as_ref().unwrap(), + None => + unimplemented!("IndexMut not implemented for Unit"), + }; + + Ok + ( + if is_mut { - &mut self.#field_name[ index ] + qt! + { + &mut self.#field_name[ index ] + } + } + else + { + qt! + { + &self.#field_name[ index ] + } } - } - else - { - qt!{ } - } + ) } - ).collect(), - _ => - { - return Err + _ => + Err ( syn::Error::new_spanned - ( - &fields, - "Only one field can include #[ index_mut ] derive macro" + ( + &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 @@ -196,7 +222,7 @@ fn generate_struct_named_fields #[ inline( always ) ] fn index_mut( &mut self, index : usize ) -> &mut Self::Output { - #generated + #generated_index_mut } } } @@ -228,7 +254,7 @@ fn generate_struct_tuple_fields syn::Error::new_spanned ( &fields, - "No attributes specified. You must to specify #[ index_mut ] for fields or name for #[ index_mut ( name = field_name ) ] for item derive macro" + "No attributes specified. You must to specify #[ index ] for fields or name for #[ index ( name = field_name ) ] for item derive macro" ) ); }, @@ -257,7 +283,7 @@ fn generate_struct_tuple_fields syn::Error::new_spanned ( &fields, - "Only one field can include #[ index_mut ] derive macro" + "Only one field can include #[ index ] derive macro" ) ); } diff --git a/module/core/derive_tools_meta/src/derive/index_mut/field_attributes.rs b/module/core/derive_tools_meta/src/derive/index_mut/field_attributes.rs deleted file mode 100644 index 260b6edf4a..0000000000 --- a/module/core/derive_tools_meta/src/derive/index_mut/field_attributes.rs +++ /dev/null @@ -1,98 +0,0 @@ -use super::*; -use macro_tools:: -{ - ct, - Result, - AttributePropertyComponent, - AttributePropertyOptionalSingletone, - Assign, -}; - -/// -/// Attributes of a field / variant -/// - -/// Represents the attributes of a struct. Aggregates all its attributes. -#[ derive( Debug, Default ) ] -pub struct FieldAttributes -{ - /// Specifies whether we should generate IndexMut implementation for the field. - pub index_mut : AttributePropertyIndexMut, -} - -impl FieldAttributes -{ - /// 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 = ct::concatcp! - ( - "Known attributes are : ", - ", ", AttributePropertyIndexMut::KEYWORD, - ".", - ); - syn_err! - ( - attr, - "Expects an attribute of format '#[ attribute ]'\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() - { - AttributePropertyIndexMut::KEYWORD => result.assign( AttributePropertyIndexMut::from( true ) ), - _ => {}, - // _ => return Err( error( attr ) ), - } - } - - Ok( result ) - } -} - -impl< IntoT > Assign< AttributePropertyIndexMut, IntoT > for FieldAttributes -where - IntoT : Into< AttributePropertyIndexMut >, -{ - #[ inline( always ) ] - fn assign( &mut self, component : IntoT ) - { - self.index_mut.assign( component.into() ); - } -} - - -// == Attribute properties - -/// Marker type for attribute property to indicate whether a index_mut code should be generated. -/// Defaults to `false`, meaning no index_mut code is generated unless explicitly requested. -#[ derive( Debug, Default, Clone, Copy ) ] -pub struct AttributePropertyIndexMutMarker; - -impl AttributePropertyComponent for AttributePropertyIndexMutMarker -{ - const KEYWORD : & 'static str = "index_mut"; -} - -/// Indicates whether a index_mut code should be generated. -/// Defaults to `false`, meaning no index_mut code is generated unless explicitly requested. -pub type AttributePropertyIndexMut = AttributePropertyOptionalSingletone< AttributePropertyIndexMutMarker >; - -// == - - - diff --git a/module/core/derive_tools_meta/src/derive/index_mut/item_attributes.rs b/module/core/derive_tools_meta/src/derive/index_mut/item_attributes.rs deleted file mode 100644 index 81209d8b1d..0000000000 --- a/module/core/derive_tools_meta/src/derive/index_mut/item_attributes.rs +++ /dev/null @@ -1,233 +0,0 @@ -use super::*; -use macro_tools:: -{ - ct, - Result, - AttributeComponent, - AttributePropertyComponent, - AttributePropertyOptionalSyn, - AttributePropertyOptionalSingletone, -}; - -/// Represents the attributes of a struct. Aggregates all its attributes. -#[ derive( Debug, Default ) ] -pub struct ItemAttributes -{ - /// Attribute for customizing generated code. - pub index_mut : ItemAttributeIndexMut, - /// Specifies whether to provide a generated code as a hint. - /// Defaults to `false`, which means no code is printed unless explicitly requested. - pub debug : AttributePropertyDebug, -} - -#[ derive( Debug, Default ) ] -pub struct ItemAttributeIndexMut -{ - /// Specifies what specific named field must implement IndexMut. - pub name : AttributePropertyName, -} - -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 = ct::concatcp! - ( - "Known attributes are: ", - "debug", - ", ", ItemAttributeIndexMut::KEYWORD, - "." - ); - syn_err! - ( - attr, - "Expects an attribute of format '#[ attribute ]'\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() - { - ItemAttributeIndexMut::KEYWORD => result.assign( ItemAttributeIndexMut::from_meta( attr )? ), - "debug" => {}, - _ => {}, - // _ => return Err( error( attr ) ), - } - } - - Ok( result ) - } -} - -impl AttributeComponent for ItemAttributeIndexMut -{ - const KEYWORD : &'static str = "index_mut"; - - fn from_meta( attr : &syn::Attribute ) -> Result< Self > - { - match attr.meta - { - syn::Meta::List( ref meta_list ) => - { - return syn::parse2::< ItemAttributeIndexMut >( 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< ItemAttributeIndexMut, IntoT > for ItemAttributes -where - IntoT : Into< ItemAttributeIndexMut >, -{ - #[ inline( always ) ] - fn assign( &mut self, component : IntoT ) - { - self.index_mut.assign( component.into() ); - } -} - - - -impl< IntoT > Assign< AttributePropertyDebug, IntoT > for ItemAttributes -where - IntoT : Into< AttributePropertyDebug >, -{ - #[ inline( always ) ] - fn assign( &mut self, component : IntoT ) - { - self.debug = component.into(); - } -} - - -impl< IntoT > Assign< ItemAttributeIndexMut, IntoT > for ItemAttributeIndexMut -where - IntoT : Into< ItemAttributeIndexMut >, -{ - #[ inline( always ) ] - fn assign( &mut self, component : IntoT ) - { - let component = component.into(); - self.name.assign( component.name ); - } -} - -impl< IntoT > Assign< AttributePropertyName, IntoT > for ItemAttributeIndexMut -where - IntoT : Into< AttributePropertyName >, -{ - #[ inline( always ) ] - fn assign( &mut self, component : IntoT ) - { - self.name = component.into(); - } -} - - -impl syn::parse::Parse for ItemAttributeIndexMut -{ - fn parse( input : syn::parse::ParseStream< '_ > ) -> syn::Result< Self > - { - let mut result = Self::default(); - - let error = | ident : &syn::Ident | -> syn::Error - { - let known = ct::concatcp! - ( - "Known entries of attribute ", ItemAttributeIndexMut::KEYWORD, " are : ", - AttributePropertyName::KEYWORD, - ".", - ); - 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() - { - AttributePropertyName::KEYWORD => result.assign( AttributePropertyName::parse( input )? ), - _ => 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 of optional identifier that names the setter. It is parsed from inputs -/// like `name = field_name`. -#[ derive( Debug, Default, Clone, Copy ) ] -pub struct NameMarker; - -impl AttributePropertyComponent for NameMarker -{ - const KEYWORD : &'static str = "name"; -} - -/// An optional identifier that names the setter. It is parsed from inputs -/// like `name = field_name`. -pub type AttributePropertyName = AttributePropertyOptionalSyn< syn::Ident, NameMarker >; - -// = - -/// 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 >; - -// == diff --git a/module/core/derive_tools_meta/src/lib.rs b/module/core/derive_tools_meta/src/lib.rs index 31f1ac9a9d..9135104710 100644 --- a/module/core/derive_tools_meta/src/lib.rs +++ b/module/core/derive_tools_meta/src/lib.rs @@ -691,7 +691,7 @@ pub fn derive_index( input : proc_macro::TokenStream ) -> proc_macro::TokenStrea attributes ( debug, // item - index_mut, // field + index, // field ) )] pub fn derive_index_mut( input : proc_macro::TokenStream ) -> proc_macro::TokenStream From 4f167e3d527b94448b395f926b30041813ac3ffa Mon Sep 17 00:00:00 2001 From: Inkvisto Date: Thu, 11 Jul 2024 23:08:18 +0300 Subject: [PATCH 6/7] ref: #[ index_mut ] to #[ index ] naming --- .../inc/index_mut/struct_multiple_tuple.rs | 3 +- .../tests/inc/index_mut/struct_tuple.rs | 3 +- .../derive_tools_meta/src/derive/index_mut.rs | 89 ++++++++++++++----- module/core/derive_tools_meta/src/lib.rs | 5 +- 4 files changed, 70 insertions(+), 30 deletions(-) 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 index 1e9d3b07e8..41c9a21877 100644 --- 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 @@ -3,12 +3,11 @@ use super::*; -#[ derive( the_module::Index, the_module::IndexMut ) ] +#[ derive( the_module::IndexMut ) ] struct StructMultipleTuple< T > ( bool, #[ index ] - #[ index_mut ] Vec< T > ); 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 index 3f6fbf13d0..f252344d58 100644 --- a/module/core/derive_tools/tests/inc/index_mut/struct_tuple.rs +++ b/module/core/derive_tools/tests/inc/index_mut/struct_tuple.rs @@ -2,11 +2,10 @@ #[ allow( unused_imports ) ] use super::*; -#[ derive( the_module::Index, the_module::IndexMut ) ] +#[ derive( the_module::IndexMut ) ] struct StructTuple< T > ( #[ index ] - #[ index_mut ] Vec< T > ); diff --git a/module/core/derive_tools_meta/src/derive/index_mut.rs b/module/core/derive_tools_meta/src/derive/index_mut.rs index 561b32c3e5..63a8ab7ed7 100644 --- a/module/core/derive_tools_meta/src/derive/index_mut.rs +++ b/module/core/derive_tools_meta/src/derive/index_mut.rs @@ -245,55 +245,98 @@ fn generate_struct_tuple_fields .filter( | field | !field.attrs.is_empty() ) .collect(); - let generated = match non_empty_attrs.len() + + let generate = | is_mut : bool | + -> Result< proc_macro2::TokenStream > { - 0 => - { - return Err - ( - syn::Error::new_spanned - ( - &fields, - "No attributes specified. You must to specify #[ index ] for fields or name for #[ index ( name = field_name ) ] for item derive macro" + 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 + }, + 1 => fields + .iter() + .enumerate() + .map ( | ( i, field ) | { let i = syn::Index::from( i ); if !field.attrs.is_empty() { - qt! - { - &mut self.#i[ index ] - } + Ok + ( + if is_mut + { + qt!{&mut self.#i[ index ]} + } + else + { + qt!{&self.#i[ index ] } + } + ) } else { - qt!{ } + Ok + ( + qt!{ } + ) } } - ), + ).collect(), _ => - { - return Err + 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 @@ -301,7 +344,7 @@ fn generate_struct_tuple_fields #[ inline( always ) ] fn index_mut( &mut self, index : usize ) -> &mut Self::Output { - #( #generated )* + #generated_mut } } } diff --git a/module/core/derive_tools_meta/src/lib.rs b/module/core/derive_tools_meta/src/lib.rs index 9135104710..0bf7a79669 100644 --- a/module/core/derive_tools_meta/src/lib.rs +++ b/module/core/derive_tools_meta/src/lib.rs @@ -669,15 +669,14 @@ pub fn derive_index( input : proc_macro::TokenStream ) -> proc_macro::TokenStrea /// } /// ``` /// -/// Use `#[ index_mut ]` on field or `#[ index_mut( name = field_name )]` on named items to automatically generate the implementation: +/// Use `#[ index ]` on field or `#[ index( name = field_name )]` on named items to automatically generate the implementation: /// /// ```rust /// use derive_tools_meta::*; -/// #[derive( Index, IndexMut )] +/// #[derive( IndexMut )] /// pub struct IsTransparent< T > /// { /// #[ index ] -/// #[ index_mut ] /// a : Vec< T > /// }; /// ``` From 1f158a34a544f651be5262517e7903325c1fae72 Mon Sep 17 00:00:00 2001 From: Inkvisto Date: Fri, 12 Jul 2024 10:41:38 +0300 Subject: [PATCH 7/7] fut: add compiletime and collision tests. ref: index_mut macros --- .../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 +++++ .../inc/index_mut/only_test/struct_named.rs | 2 +- .../tests/inc/index_mut/struct_collisions.rs | 22 ++++++++++++++ ...amed.rs => struct_multiple_named_field.rs} | 0 .../index_mut/struct_multiple_named_item.rs | 15 ++++++++++ module/core/derive_tools/tests/inc/mod.rs | 21 ++++++++++++- .../derive_tools_meta/src/derive/index_mut.rs | 30 ++++++++++++------- 14 files changed, 153 insertions(+), 12 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/struct_collisions.rs rename module/core/derive_tools/tests/inc/index_mut/{struct_multiple_named.rs => struct_multiple_named_field.rs} (100%) create mode 100644 module/core/derive_tools/tests/inc/index_mut/struct_multiple_named_item.rs 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_named.rs b/module/core/derive_tools/tests/inc/index_mut/only_test/struct_named.rs index f3e4a0fa19..c2e20f82fe 100644 --- 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 @@ -3,7 +3,7 @@ fn index_mut() { let mut x = StructNamed { - a: vec![ 4, 17 ] + a : vec![ 4, 17 ] }; x[ 0 ] = 5; 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.rs b/module/core/derive_tools/tests/inc/index_mut/struct_multiple_named_field.rs similarity index 100% rename from module/core/derive_tools/tests/inc/index_mut/struct_multiple_named.rs rename to module/core/derive_tools/tests/inc/index_mut/struct_multiple_named_field.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/mod.rs b/module/core/derive_tools/tests/inc/mod.rs index 89d12692e2..6f46e324f5 100644 --- a/module/core/derive_tools/tests/inc/mod.rs +++ b/module/core/derive_tools/tests/inc/mod.rs @@ -339,12 +339,31 @@ mod index_mut_tests #[ allow( unused_imports ) ] use super::*; mod struct_named; - mod struct_multiple_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/src/derive/index_mut.rs b/module/core/derive_tools_meta/src/derive/index_mut.rs index 63a8ab7ed7..fc72715eea 100644 --- a/module/core/derive_tools_meta/src/derive/index_mut.rs +++ b/module/core/derive_tools_meta/src/derive/index_mut.rs @@ -113,11 +113,11 @@ fn generate_struct_named_fields let fields = fields.named.clone(); let attr_name = &item_attrs.index.name.clone().internal(); - let field_attrs: Vec<&syn::Field> = fields + let field_attrs: Vec< &syn::Field > = fields .iter() .filter ( - |field| + | field | { FieldAttributes::from_attrs( field.attrs.iter() ).map_or ( @@ -135,9 +135,19 @@ fn generate_struct_named_fields { Ok ( - qt! + if is_mut + { + qt! + { + &mut self.#attr_name[ index ] + } + } + else { - &self.#attr_name[index] + qt! + { + &self.#attr_name[ index ] + } } ) } @@ -150,7 +160,7 @@ fn generate_struct_named_fields let field_name = match field_attrs .first() - .map(|&field| field) + .cloned() .or_else ( || fields.first() @@ -159,7 +169,7 @@ fn generate_struct_named_fields Some( field ) => field.ident.as_ref().unwrap(), None => - unimplemented!("IndexMut not implemented for Unit"), + unimplemented!( "IndexMut not implemented for Unit" ), }; Ok @@ -194,8 +204,8 @@ fn generate_struct_named_fields }; - let generated_index = generate(false)?; - let generated_index_mut = generate(true)?; + let generated_index = generate( false )?; + let generated_index_mut = generate( true )?; Ok ( @@ -316,8 +326,8 @@ fn generate_struct_tuple_fields - let generated = generate(false)?; - let generated_mut = generate(true)?; + let generated = generate( false )?; + let generated_mut = generate( true )?; Ok (