From 0d799fa7e713e7ef60e09cfc0546c2f1b04595b5 Mon Sep 17 00:00:00 2001 From: Inkvisto Date: Tue, 9 Jul 2024 08:32:33 +0300 Subject: [PATCH 1/8] fut: add expected implementation of syntax in test --- .../core/derive_tools/tests/inc/index/struct_multiple_named.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/core/derive_tools/tests/inc/index/struct_multiple_named.rs b/module/core/derive_tools/tests/inc/index/struct_multiple_named.rs index 3dea73695e..e2751673f8 100644 --- a/module/core/derive_tools/tests/inc/index/struct_multiple_named.rs +++ b/module/core/derive_tools/tests/inc/index/struct_multiple_named.rs @@ -3,10 +3,10 @@ use super::*; #[ derive( the_module::Index ) ] +#[ index ( name = b ) ] struct StructMultipleNamed< T > { a : Vec< T >, - #[ index ] b : Vec< T >, } From 1eb5d48dcff0d28d879fead190b070bdfef79769 Mon Sep 17 00:00:00 2001 From: Inkvisto Date: Tue, 9 Jul 2024 13:39:04 +0300 Subject: [PATCH 2/8] fut: add more test cases, item_attributes refactor and index macro --- .../tests/inc/index/compiletime/struct.rs | 2 +- .../tests/inc/index/compiletime/struct.stderr | 4 +- .../inc/index/compiletime/struct_no_attrs.rs | 14 ++ .../index/compiletime/struct_no_attrs.stderr | 6 + .../tests/inc/index/struct_collisions.rs | 23 +++ .../inc/index/struct_multiple_named_field.rs | 14 ++ ...named.rs => struct_multiple_named_item.rs} | 0 module/core/derive_tools/tests/inc/mod.rs | 7 +- .../derive_tools_meta/src/derive/index.rs | 166 +++++++++++----- .../src/derive/index/item_attributes.rs | 177 +++++++++++++++++- 10 files changed, 347 insertions(+), 66 deletions(-) create mode 100644 module/core/derive_tools/tests/inc/index/compiletime/struct_no_attrs.rs create mode 100644 module/core/derive_tools/tests/inc/index/compiletime/struct_no_attrs.stderr create mode 100644 module/core/derive_tools/tests/inc/index/struct_collisions.rs create mode 100644 module/core/derive_tools/tests/inc/index/struct_multiple_named_field.rs rename module/core/derive_tools/tests/inc/index/{struct_multiple_named.rs => struct_multiple_named_item.rs} (100%) diff --git a/module/core/derive_tools/tests/inc/index/compiletime/struct.rs b/module/core/derive_tools/tests/inc/index/compiletime/struct.rs index 1b9d3785a8..df10669a10 100644 --- a/module/core/derive_tools/tests/inc/index/compiletime/struct.rs +++ b/module/core/derive_tools/tests/inc/index/compiletime/struct.rs @@ -4,7 +4,7 @@ use derive_tools::Index; struct StructMultipleNamed< T > { #[ index ] - a: Vec< T >, + a : Vec< T >, #[ index ] b : Vec< T >, } diff --git a/module/core/derive_tools/tests/inc/index/compiletime/struct.stderr b/module/core/derive_tools/tests/inc/index/compiletime/struct.stderr index e150d4f21d..2410de4629 100644 --- a/module/core/derive_tools/tests/inc/index/compiletime/struct.stderr +++ b/module/core/derive_tools/tests/inc/index/compiletime/struct.stderr @@ -1,8 +1,8 @@ -error: Only one field can include #[index] derive macro +error: Only one field can include #[ index ] derive macro --> tests/inc/index/compiletime/struct.rs:6:3 | 6 | / #[ index ] -7 | | a: Vec< T >, +7 | | a : Vec< T >, 8 | | #[ index ] 9 | | b : Vec< T >, | |_______________^ diff --git a/module/core/derive_tools/tests/inc/index/compiletime/struct_no_attrs.rs b/module/core/derive_tools/tests/inc/index/compiletime/struct_no_attrs.rs new file mode 100644 index 0000000000..e4cac3a605 --- /dev/null +++ b/module/core/derive_tools/tests/inc/index/compiletime/struct_no_attrs.rs @@ -0,0 +1,14 @@ +use derive_tools::Index; + +#[ derive( Index ) ] +#[ index () ] +struct StructMultipleNamed< T > +{ + a : Vec< T >, + b : Vec< T >, +} + +fn main() +{ +} + diff --git a/module/core/derive_tools/tests/inc/index/compiletime/struct_no_attrs.stderr b/module/core/derive_tools/tests/inc/index/compiletime/struct_no_attrs.stderr new file mode 100644 index 0000000000..4e22932b2c --- /dev/null +++ b/module/core/derive_tools/tests/inc/index/compiletime/struct_no_attrs.stderr @@ -0,0 +1,6 @@ +error: No attributes specified. You must to specify #[ index ] for fields or name for #[ index ( name = field_name ) ] for item derive macro + --> tests/inc/index/compiletime/struct_no_attrs.rs:7:3 + | +7 | / a : Vec< T >, +8 | | b : Vec< T >, + | |_______________^ diff --git a/module/core/derive_tools/tests/inc/index/struct_collisions.rs b/module/core/derive_tools/tests/inc/index/struct_collisions.rs new file mode 100644 index 0000000000..5d000f096c --- /dev/null +++ b/module/core/derive_tools/tests/inc/index/struct_collisions.rs @@ -0,0 +1,23 @@ +#![ 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::Index, the_module::From ) ] +#[ allow( dead_code ) ] +struct StructMultipleNamed< T > +{ + #[ from ( on ) ] + a : Vec< T >, + #[ index ] + b : Vec< T >, +} + +include!( "./only_test/struct_multiple_named.rs" ); + diff --git a/module/core/derive_tools/tests/inc/index/struct_multiple_named_field.rs b/module/core/derive_tools/tests/inc/index/struct_multiple_named_field.rs new file mode 100644 index 0000000000..a99e72a7b5 --- /dev/null +++ b/module/core/derive_tools/tests/inc/index/struct_multiple_named_field.rs @@ -0,0 +1,14 @@ +#![ allow( dead_code ) ] +#[ allow( unused_imports ) ] +use super::*; + +#[ derive( the_module::Index ) ] +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/struct_multiple_named.rs b/module/core/derive_tools/tests/inc/index/struct_multiple_named_item.rs similarity index 100% rename from module/core/derive_tools/tests/inc/index/struct_multiple_named.rs rename to module/core/derive_tools/tests/inc/index/struct_multiple_named_item.rs diff --git a/module/core/derive_tools/tests/inc/mod.rs b/module/core/derive_tools/tests/inc/mod.rs index feff00a160..94c3d2835d 100644 --- a/module/core/derive_tools/tests/inc/mod.rs +++ b/module/core/derive_tools/tests/inc/mod.rs @@ -305,14 +305,16 @@ mod index_tests 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 ] @@ -325,6 +327,7 @@ mod index_tests t.compile_fail( "tests/inc/index/compiletime/struct.rs" ); t.compile_fail( "tests/inc/index/compiletime/struct_unit.rs" ); + t.compile_fail( "tests/inc/index/compiletime/struct_no_attrs.rs" ); t.compile_fail( "tests/inc/index/compiletime/struct_named_empty.rs" ); t.compile_fail( "tests/inc/index/compiletime/enum.rs" ); } diff --git a/module/core/derive_tools_meta/src/derive/index.rs b/module/core/derive_tools_meta/src/derive/index.rs index 19a68ef63b..ede614aa42 100644 --- a/module/core/derive_tools_meta/src/derive/index.rs +++ b/module/core/derive_tools_meta/src/derive/index.rs @@ -8,12 +8,22 @@ use macro_tools:: 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( 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() ); @@ -24,6 +34,7 @@ pub fn index( input : proc_macro::TokenStream ) -> Result< proc_macro2::TokenStr generate_struct ( item_name, + &item_attrs, &generics_impl, &generics_ty, &generics_where, @@ -49,6 +60,7 @@ pub fn index( input : proc_macro::TokenStream ) -> Result< proc_macro2::TokenStr 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 >, @@ -63,6 +75,7 @@ fn generate_struct generate_struct_named_fields ( item_name, + &item_attrs, generics_impl, generics_ty, generics_where, @@ -88,6 +101,7 @@ fn generate_struct 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 >, @@ -95,39 +109,73 @@ fn generate_struct_named_fields ) -> Result< proc_macro2::TokenStream > { + let fields = fields.named.clone(); - let non_empty_attrs : Vec< &syn::Field > = fields.iter().filter(| field | - !field.attrs.is_empty() + let attr_name = &item_attrs.index.name.clone().internal(); + + let field_attrs : Vec< &syn::Field > = fields.iter().filter( | field | + { + let field_attrs = FieldAttributes::from_attrs( field.attrs.iter() ).unwrap(); + return field_attrs.index.value( false ) + } ).collect(); - if non_empty_attrs.len() != 1 - { - return Err( - syn::Error::new_spanned - ( - &fields, - "Only one field can include #[index] derive macro" - ) - ); - } - let generated = fields.iter().map(| field | + let generated = if let Some(attr_name) = attr_name + { + qt! { - let field_name = &field.ident; - - if !field.attrs.is_empty() + &self.#attr_name[ index ] + } + } + else + { + match field_attrs.len() { - qt! + 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" + ) + ); + }, + 1 => field_attrs.iter().map + ( + | field | + { + let field_name = &field.ident; + + if !field.attrs.is_empty() + { + qt! + { + &self.#field_name[ index ] + } + } + else + { + qt!{ } + } + } + ).collect(), + _ => { - &self.#field_name[ index ] + return Err + ( + syn::Error::new_spanned + ( + &fields, + "Only one field can include #[ index ] derive macro" + ) + ); } } - else - { - qt!{ } - } - }); - + }; + Ok ( qt! @@ -141,7 +189,7 @@ fn generate_struct_named_fields #[ inline( always ) ] fn index( &self, index : usize ) -> &Self::Output { - #( #generated )* + #generated } } } @@ -159,36 +207,52 @@ fn generate_struct_tuple_fields -> 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(); - - if non_empty_attrs.len() != 1 + let non_empty_attrs : Vec< &syn::Field > = fields.iter().filter( | field | !field.attrs.is_empty() ).collect(); + + let generated = match non_empty_attrs.len() { - return Err( - syn::Error::new_spanned - ( - &fields, - "Only one field can include #[index] derive macro" - ) - ); - } - - let generated = fields.iter().enumerate().map(|( i, field )| - { - let i = syn::Index::from( i ); - if !field.attrs.is_empty() { - qt! - { - &self.#i[ index ] + 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" + ) + ); + }, + 1 => fields.iter().enumerate().map + ( + | ( i, field ) | + { + let i = syn::Index::from( i ); + if !field.attrs.is_empty() + { + qt! + { + &self.#i[ index ] + } + } + else + { + qt!{ } + } } - } - else + ), + _ => { - qt!{ } + return Err + ( + syn::Error::new_spanned + ( + &fields, + "Only one field can include #[ index ] derive macro" + ) + ); } - }); - + }; + Ok ( qt! diff --git a/module/core/derive_tools_meta/src/derive/index/item_attributes.rs b/module/core/derive_tools_meta/src/derive/index/item_attributes.rs index 0e223789e0..8cfc9924cf 100644 --- a/module/core/derive_tools_meta/src/derive/index/item_attributes.rs +++ b/module/core/derive_tools_meta/src/derive/index/item_attributes.rs @@ -1,21 +1,32 @@ +use super::*; use macro_tools:: { ct, - syn_err, - syn, - qt, Result, + AttributeComponent, AttributePropertyComponent, AttributePropertyOptionalSingletone, + AttributePropertyOptionalSyn, }; /// Represents the attributes of a struct. Aggregates all its attributes. #[ derive( Debug, Default ) ] pub struct ItemAttributes { + /// Attribute for customizing generated code. + pub index : ItemAttributeIndex, + /// Specifies whether to print a sketch of generated `Index` or not. + /// Defaults to `false`, which means no code is printed unless explicitly requested. pub debug : AttributePropertyDebug, } +#[ derive( Debug, Default ) ] +pub struct ItemAttributeIndex +{ + /// Specifies what specific named field must implement Index. + pub name : AttributePropertyName, +} + impl ItemAttributes { /// Constructs a `ItemAttributes` instance from an iterator of attributes. @@ -24,7 +35,7 @@ impl ItemAttributes /// appropriate fields in the `ItemAttributes` struct. pub fn from_attrs< 'a >( attrs : impl Iterator< Item = & 'a syn::Attribute > ) -> Result< Self > { - let result = Self::default(); + let mut result = Self::default(); // Closure to generate an error message for unknown attributes. let error = | attr : & syn::Attribute | -> syn::Error @@ -33,6 +44,7 @@ impl ItemAttributes ( "Known attributes are: ", "debug", + ", ", ItemAttributeIndex::KEYWORD, "." ); syn_err! @@ -49,6 +61,7 @@ impl ItemAttributes let key_str = format!( "{}", key_ident ); match key_str.as_ref() { + ItemAttributeIndex::KEYWORD => result.assign( ItemAttributeIndex::from_meta( attr )? ), "debug" => {}, _ => {}, // _ => return Err( error( attr ) ), @@ -59,22 +72,166 @@ impl ItemAttributes } } +impl AttributeComponent for ItemAttributeIndex +{ + const KEYWORD : &'static str = "index"; + + fn from_meta( attr : &syn::Attribute ) -> Result< Self > + { + match attr.meta + { + syn::Meta::List( ref meta_list ) => + { + return syn::parse2::< ItemAttributeIndex >( 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< ItemAttributeIndex, IntoT > for ItemAttributes +where + IntoT : Into< ItemAttributeIndex >, +{ + #[ inline( always ) ] + fn assign( &mut self, component : IntoT ) + { + self.index.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< ItemAttributeIndex, IntoT > for ItemAttributeIndex +where + IntoT : Into< ItemAttributeIndex >, +{ + #[ inline( always ) ] + fn assign( &mut self, component : IntoT ) + { + let component = component.into(); + self.name.assign( component.name ); + } +} + +impl< IntoT > Assign< AttributePropertyName, IntoT > for ItemAttributeIndex +where + IntoT : Into< AttributePropertyName >, +{ + #[ inline( always ) ] + fn assign( &mut self, component : IntoT ) + { + self.name = component.into(); + } +} + + +impl syn::parse::Parse for ItemAttributeIndex +{ + 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 ", ItemAttributeIndex::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 to specify whether to provide a sketch as a hint. -/// Defaults to `false`, which means no hint is provided unless explicitly requested. +/// Marker type for attribute property of optional identifier that names the setter. It is parsed from inputs +/// like `name = my_field`. +#[ derive( Debug, Default, Clone, Copy ) ] +pub struct NameMarker; + +impl AttributePropertyComponent for NameMarker +{ + const KEYWORD : &'static str = "name"; +} + +/// An optional identifier that names the setter. It is parsed from inputs +/// like `name = my_field`. +pub type AttributePropertyName = AttributePropertyOptionalSyn< syn::Ident, 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"; + const KEYWORD : &'static str = "debug"; } -/// Specifies whether to provide a sketch as a hint. -/// Defaults to `false`, which means no hint is provided unless explicitly requested. +/// 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 34e7def91f3f2f74793b28856fce6aa6d3aa13bf Mon Sep 17 00:00:00 2001 From: Inkvisto Date: Tue, 9 Jul 2024 22:54:31 +0300 Subject: [PATCH 3/8] ref: formatting and refactor to not use unwrap --- .../derive_tools_meta/src/derive/index.rs | 27 +++++++++++++------ .../src/derive/index/item_attributes.rs | 12 +++------ 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/module/core/derive_tools_meta/src/derive/index.rs b/module/core/derive_tools_meta/src/derive/index.rs index ede614aa42..236d054345 100644 --- a/module/core/derive_tools_meta/src/derive/index.rs +++ b/module/core/derive_tools_meta/src/derive/index.rs @@ -113,12 +113,20 @@ 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.iter().filter( | field | - { - let field_attrs = FieldAttributes::from_attrs( field.attrs.iter() ).unwrap(); - return field_attrs.index.value( false ) - } - ).collect(); + 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 generated = if let Some(attr_name) = attr_name @@ -189,7 +197,7 @@ fn generate_struct_named_fields #[ inline( always ) ] fn index( &self, index : usize ) -> &Self::Output { - #generated + #generated } } } @@ -207,7 +215,10 @@ fn generate_struct_tuple_fields -> 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 non_empty_attrs : Vec< &syn::Field > = fields + .iter() + .filter( | field | !field.attrs.is_empty() ) + .collect(); let generated = match non_empty_attrs.len() { diff --git a/module/core/derive_tools_meta/src/derive/index/item_attributes.rs b/module/core/derive_tools_meta/src/derive/index/item_attributes.rs index 8cfc9924cf..33a056e248 100644 --- a/module/core/derive_tools_meta/src/derive/index/item_attributes.rs +++ b/module/core/derive_tools_meta/src/derive/index/item_attributes.rs @@ -5,8 +5,8 @@ use macro_tools:: Result, AttributeComponent, AttributePropertyComponent, - AttributePropertyOptionalSingletone, AttributePropertyOptionalSyn, + AttributePropertyOptionalSingletone, }; /// Represents the attributes of a struct. Aggregates all its attributes. @@ -15,7 +15,7 @@ pub struct ItemAttributes { /// Attribute for customizing generated code. pub index : ItemAttributeIndex, - /// Specifies whether to print a sketch of generated `Index` or not. + /// 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, } @@ -201,7 +201,7 @@ impl syn::parse::Parse for ItemAttributeIndex // == Attribute properties /// Marker type for attribute property of optional identifier that names the setter. It is parsed from inputs -/// like `name = my_field`. +/// like `name = field_name`. #[ derive( Debug, Default, Clone, Copy ) ] pub struct NameMarker; @@ -211,7 +211,7 @@ impl AttributePropertyComponent for NameMarker } /// An optional identifier that names the setter. It is parsed from inputs -/// like `name = my_field`. +/// like `name = field_name`. pub type AttributePropertyName = AttributePropertyOptionalSyn< syn::Ident, NameMarker >; // = @@ -231,7 +231,3 @@ impl AttributePropertyComponent for AttributePropertyDebugMarker pub type AttributePropertyDebug = AttributePropertyOptionalSingletone< AttributePropertyDebugMarker >; // == - - - - From 0e5795e68158a0425b21eac4f85a0bcedf057e6f Mon Sep 17 00:00:00 2001 From: Inkvisto Date: Wed, 10 Jul 2024 13:32:01 +0300 Subject: [PATCH 4/8] ref: formatting tests --- .../tests/inc/index/struct_multiple_named_manual.rs | 4 ++-- .../core/derive_tools/tests/inc/index/struct_named_manual.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/module/core/derive_tools/tests/inc/index/struct_multiple_named_manual.rs b/module/core/derive_tools/tests/inc/index/struct_multiple_named_manual.rs index 6e5bc2cba2..ff3d26f7e2 100644 --- a/module/core/derive_tools/tests/inc/index/struct_multiple_named_manual.rs +++ b/module/core/derive_tools/tests/inc/index/struct_multiple_named_manual.rs @@ -3,8 +3,8 @@ use core::ops::Index; #[ allow( dead_code ) ] struct StructMultipleNamed< T > { - a: Vec< T >, - b: Vec< T >, + a : Vec< T >, + b : Vec< T >, } impl< T > Index< usize > for StructMultipleNamed< T > diff --git a/module/core/derive_tools/tests/inc/index/struct_named_manual.rs b/module/core/derive_tools/tests/inc/index/struct_named_manual.rs index f09d4bbeb1..e66ce4131d 100644 --- a/module/core/derive_tools/tests/inc/index/struct_named_manual.rs +++ b/module/core/derive_tools/tests/inc/index/struct_named_manual.rs @@ -3,7 +3,7 @@ use core::ops::Index; #[ allow( dead_code ) ] struct StructNamed< T > { - a: Vec< T > + a : Vec< T > } impl< T > Index< usize > for StructNamed< T > From e7db365b7d97884f91c589e5119fb5b7defb67e4 Mon Sep 17 00:00:00 2001 From: Inkvisto Date: Wed, 10 Jul 2024 13:40:06 +0300 Subject: [PATCH 5/8] ref: formatting tests --- .../tests/inc/index/only_test/struct_multiple_named.rs | 4 ++-- .../derive_tools/tests/inc/index/only_test/struct_named.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/module/core/derive_tools/tests/inc/index/only_test/struct_multiple_named.rs b/module/core/derive_tools/tests/inc/index/only_test/struct_multiple_named.rs index 6153f8751e..50ea4f671a 100644 --- a/module/core/derive_tools/tests/inc/index/only_test/struct_multiple_named.rs +++ b/module/core/derive_tools/tests/inc/index/only_test/struct_multiple_named.rs @@ -3,8 +3,8 @@ fn index() { let x = StructMultipleNamed { - a: vec![ 12, 22 ], - b: vec![ 33, 55 ] + a : vec![ 12, 22 ], + b : vec![ 33, 55 ] }; let v = vec![ 33, 55 ]; let exp = ( v[ 0 ], v[ 1 ] ); diff --git a/module/core/derive_tools/tests/inc/index/only_test/struct_named.rs b/module/core/derive_tools/tests/inc/index/only_test/struct_named.rs index 53b2ab3f79..2d17264939 100644 --- a/module/core/derive_tools/tests/inc/index/only_test/struct_named.rs +++ b/module/core/derive_tools/tests/inc/index/only_test/struct_named.rs @@ -3,7 +3,7 @@ fn index() { let x = StructNamed { - a: vec![ false, true ] + a : vec![ false, true ] }; let v = vec![ false, true ]; let exp = ( v[ 0 ], v[ 1 ] ); From 0761a1a143e072d6e92c3d7a9bc3057f4deca5cb Mon Sep 17 00:00:00 2001 From: Inkvisto Date: Wed, 10 Jul 2024 17:45:41 +0300 Subject: [PATCH 6/8] ref: add and refactor comments --- .../derive_tools_meta/src/derive/index.rs | 63 ++++++++++++++++++- module/core/derive_tools_meta/src/lib.rs | 6 +- 2 files changed, 67 insertions(+), 2 deletions(-) diff --git a/module/core/derive_tools_meta/src/derive/index.rs b/module/core/derive_tools_meta/src/derive/index.rs index 236d054345..671e22b574 100644 --- a/module/core/derive_tools_meta/src/derive/index.rs +++ b/module/core/derive_tools_meta/src/derive/index.rs @@ -97,7 +97,37 @@ fn generate_struct } } - +/// Generates `Index` implementation for named structs +/// +/// # Example +/// +/// ## Input +/// # use derive_tools_meta::Index; +/// #[ derive( Index ) ] +/// pub struct IsTransparent +/// { +/// #[ index ] +/// value : Vec< u8 >, +/// } +/// +/// ## Output +/// ```rust +/// pub struct IsTransparent +/// { +/// value : Vec< u8 >, +/// } +/// #[ automatically_derived ] +/// impl ::core::ops::Index< usize > for IsTransparent +/// { +/// type Output = u8; +/// #[ inline( always ) ] +/// fn index( &self, index : usize ) -> &Self::Output +/// { +/// &self.value[ index ] +/// } +/// } +/// ``` +/// fn generate_struct_named_fields ( item_name : &syn::Ident, @@ -204,6 +234,37 @@ fn generate_struct_named_fields ) } +/// Generates `Index` implementation for tuple structs +/// +/// # Example +/// +/// ## Input +/// # use derive_tools_meta::Index; +/// #[ derive( Index ) ] +/// pub struct IsTransparent +/// ( +/// #[ index ] +/// Vec< u8 > +/// ); +/// +/// ## Output +/// ```rust +/// pub struct IsTransparent +/// ( +/// Vec< u8 > +/// ); +/// #[ automatically_derived ] +/// impl ::core::ops::Index< usize > for IsTransparent +/// { +/// type Output = u8; +/// #[ inline( always ) ] +/// fn index( &self, index : usize ) -> &Self::Output +/// { +/// &self.0[ index ] +/// } +/// } +/// ``` +/// fn generate_struct_tuple_fields ( item_name : &syn::Ident, diff --git a/module/core/derive_tools_meta/src/lib.rs b/module/core/derive_tools_meta/src/lib.rs index 05aaebac0a..f904871f4e 100644 --- a/module/core/derive_tools_meta/src/lib.rs +++ b/module/core/derive_tools_meta/src/lib.rs @@ -582,6 +582,7 @@ pub fn phantom( _attr: proc_macro::TokenStream, input : proc_macro::TokenStream /// /// ```rust /// use core::ops::Index; +/// /// pub struct IsTransparent< T > /// { /// a : Vec< T >, @@ -602,9 +603,12 @@ pub fn phantom( _attr: proc_macro::TokenStream, input : proc_macro::TokenStream /// Use `#[ index ]` to automatically generate the implementation: /// /// ```rust -/// # use derive_tools_meta::*; +/// use derive_tools_meta::*; +/// +/// #[ derive( Index ) ] /// pub struct IsTransparent< T > /// { +/// #[ index ] /// a : Vec< T > /// }; /// ``` From 67b05a7890d30a87710f9bcaea4cb5d3d811e835 Mon Sep 17 00:00:00 2001 From: Inkvisto Date: Thu, 11 Jul 2024 21:02:36 +0300 Subject: [PATCH 7/8] ref: delete no attrs test and fix macros implementation --- .../inc/index/compiletime/struct_no_attrs.rs | 14 -- .../index/compiletime/struct_no_attrs.stderr | 6 - module/core/derive_tools/tests/inc/mod.rs | 1 - .../derive_tools_meta/src/derive/index.rs | 141 +++++++++--------- 4 files changed, 72 insertions(+), 90 deletions(-) delete mode 100644 module/core/derive_tools/tests/inc/index/compiletime/struct_no_attrs.rs delete mode 100644 module/core/derive_tools/tests/inc/index/compiletime/struct_no_attrs.stderr diff --git a/module/core/derive_tools/tests/inc/index/compiletime/struct_no_attrs.rs b/module/core/derive_tools/tests/inc/index/compiletime/struct_no_attrs.rs deleted file mode 100644 index e4cac3a605..0000000000 --- a/module/core/derive_tools/tests/inc/index/compiletime/struct_no_attrs.rs +++ /dev/null @@ -1,14 +0,0 @@ -use derive_tools::Index; - -#[ derive( Index ) ] -#[ index () ] -struct StructMultipleNamed< T > -{ - a : Vec< T >, - b : Vec< T >, -} - -fn main() -{ -} - diff --git a/module/core/derive_tools/tests/inc/index/compiletime/struct_no_attrs.stderr b/module/core/derive_tools/tests/inc/index/compiletime/struct_no_attrs.stderr deleted file mode 100644 index 4e22932b2c..0000000000 --- a/module/core/derive_tools/tests/inc/index/compiletime/struct_no_attrs.stderr +++ /dev/null @@ -1,6 +0,0 @@ -error: No attributes specified. You must to specify #[ index ] for fields or name for #[ index ( name = field_name ) ] for item derive macro - --> tests/inc/index/compiletime/struct_no_attrs.rs:7:3 - | -7 | / a : Vec< T >, -8 | | b : Vec< T >, - | |_______________^ diff --git a/module/core/derive_tools/tests/inc/mod.rs b/module/core/derive_tools/tests/inc/mod.rs index 94c3d2835d..020cb5beb2 100644 --- a/module/core/derive_tools/tests/inc/mod.rs +++ b/module/core/derive_tools/tests/inc/mod.rs @@ -327,7 +327,6 @@ mod index_tests t.compile_fail( "tests/inc/index/compiletime/struct.rs" ); t.compile_fail( "tests/inc/index/compiletime/struct_unit.rs" ); - t.compile_fail( "tests/inc/index/compiletime/struct_no_attrs.rs" ); t.compile_fail( "tests/inc/index/compiletime/struct_named_empty.rs" ); t.compile_fail( "tests/inc/index/compiletime/enum.rs" ); } diff --git a/module/core/derive_tools_meta/src/derive/index.rs b/module/core/derive_tools_meta/src/derive/index.rs index 671e22b574..1a90d4c5a3 100644 --- a/module/core/derive_tools_meta/src/derive/index.rs +++ b/module/core/derive_tools_meta/src/derive/index.rs @@ -159,60 +159,56 @@ fn generate_struct_named_fields .collect(); - let generated = if let Some(attr_name) = attr_name + let generated = if let Some( attr_name ) = attr_name { - qt! - { - &self.#attr_name[ index ] - } + Ok + ( + qt! + { + &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 ] for fields or name for #[ index ( name = field_name ) ] for item derive macro" - ) - ); - }, - 1 => field_attrs.iter().map - ( - | field | + 0 | 1 => + { + let field_name = + match field_attrs + .first() + .copied() + .or_else + ( + || fields.first() + ) { - let field_name = &field.ident; - - if !field.attrs.is_empty() - { - qt! - { - &self.#field_name[ index ] - } - } - else + Some( field ) => + field.ident.as_ref().unwrap(), + None => + unimplemented!("IndexMut not implemented for Unit"), + }; + + Ok + ( + qt! { - qt!{ } + &self.#field_name[ index ] } - } - ).collect(), - _ => - { - return Err - ( - syn::Error::new_spanned - ( - &fields, - "Only one field can include #[ index ] derive macro" - ) - ); + ) } + _ => + Err + ( + syn::Error::new_spanned + ( + &fields, + "Only one field can include #[ index ] derive macro" + ) + ), } - }; + }?; Ok ( @@ -284,46 +280,53 @@ fn generate_struct_tuple_fields let generated = match non_empty_attrs.len() { 0 => - { - return Err + { + Ok ( - 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" - ) - ); + 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() { + Ok + ( qt! - { - &self.#i[ index ] - } + { + &self.#i[ index ] + } + ) } else { - qt!{ } + Ok + ( + qt!{ } + ) } } - ), + ).collect(), _ => - { - return Err - ( - syn::Error::new_spanned - ( - &fields, - "Only one field can include #[ index ] derive macro" - ) - ); - } - }; + Err + ( + syn::Error::new_spanned + ( + &fields, + "Only one field can include #[ index ] derive macro" + ) + ), + }?; Ok ( @@ -338,7 +341,7 @@ fn generate_struct_tuple_fields #[ inline( always ) ] fn index( &self, index : usize ) -> &Self::Output { - #( #generated )* + #generated } } } From 9282ba9f8985c6228bcc785ea1163b66c4846969 Mon Sep 17 00:00:00 2001 From: Inkvisto Date: Thu, 11 Jul 2024 23:17:26 +0300 Subject: [PATCH 8/8] ref: formatting index macros --- module/core/derive_tools_meta/src/derive/index.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/module/core/derive_tools_meta/src/derive/index.rs b/module/core/derive_tools_meta/src/derive/index.rs index 1a90d4c5a3..742d210264 100644 --- a/module/core/derive_tools_meta/src/derive/index.rs +++ b/module/core/derive_tools_meta/src/derive/index.rs @@ -143,11 +143,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 ( @@ -187,7 +187,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 @@ -322,8 +322,8 @@ fn generate_struct_tuple_fields ( syn::Error::new_spanned ( - &fields, - "Only one field can include #[ index ] derive macro" + &fields, + "Only one field can include #[ index ] derive macro" ) ), }?;