diff --git a/module/core/derive_tools_meta/src/derive/from.rs b/module/core/derive_tools_meta/src/derive/from.rs index 73b9f11f29..e0877b372e 100644 --- a/module/core/derive_tools_meta/src/derive/from.rs +++ b/module/core/derive_tools_meta/src/derive/from.rs @@ -353,172 +353,175 @@ fn generate_unit // xxx2 : get completed -// /// -// /// Attributes of a field / variant -// /// -// -// pub struct FieldAttributes -// { -// pub from : Option< AttributeFrom >, -// } -// -// impl FieldAttributes -// { -// -// pub fn from_attrs< 'a >( attrs : impl Iterator< Item = &'a syn::Attribute > ) -> Result< Self > -// { -// let mut from : AttributeFrom = None; -// -// for attr in attrs -// { -// let key_ident = attr.path().get_ident() -// .ok_or_else( || syn_err!( attr, "Expects an attribute of format #[ attribute( val ) ], but got:\n {}", qt!{ #attr } ) )?; -// let key_str = format!( "{}", key_ident ); -// -// if attr::is_standard( &key_str ) -// { -// continue; -// } -// -// // qqq : qqq for Anton : xxx : refactor field_attrs::FieldAttributes::from_attrs to make it similar to this function -// match key_str.as_ref() -// { -// AttributeFrom::KEYWORD => -// { -// from.replace( AttributeFrom::from_meta( attr )? ); -// } -// "debug" => -// { -// } -// _ => -// { -// return Err( syn_err!( attr, "Known field attirbutes are : `from`, `debug`.\nUnknown structure attribute : {}", qt!{ #attr } ) ); -// } -// } -// } -// -// Ok( FieldAttributes { from } ) -// } -// -// } -// -// -// /// -// /// Attribute to hold parameters of forming for a specific field or variant. -// /// For example to avoid code From generation for it. -// /// -// /// `#[ from( off, hint : true ) ]` -// /// -// -// pub struct AttributeFrom -// { -// /// Explicitly enable generation of From for a specific field/variant. -// /// By default From is generated, but at some circumstances it's required to opt in explicitly. -// pub on : Option< syn::Ident >, -// /// Disable generation of From for a specific field/variant. -// pub off : Option< syn::Ident >, -// /// Specifies whether to provide a sketch of generated From or not. -// /// Defaults to `false`, which means no hint is provided unless explicitly requested. -// pub hint : bool, -// } -// -// impl AttributeFrom -// { -// -// const KEYWORD : &'static str = "from"; -// -// pub fn from_meta( attr : &syn::Attribute ) -> Result< Self > -// { -// match attr.meta -// { -// syn::Meta::List( ref meta_list ) => -// { -// return syn::parse2::< AttributeFrom >( meta_list.tokens.clone() ); -// }, -// syn::Meta::Path( ref _path ) => -// { -// return Ok( Default::default() ) -// }, -// _ => return_syn_err!( attr, "Expects an attribute of format #[ from( off ) ] -// .\nGot: {}", qt!{ #attr } ), -// } -// } -// -// } -// -// impl syn::parse::Parse for AttributeFrom -// { -// fn parse( input : syn::parse::ParseStream< '_ > ) -> syn::Result< Self > -// { -// let mut off : bool = false; -// let mut on : bool = false; -// let mut hint = false; -// -// while !input.is_empty() -// { -// let lookahead = input.lookahead1(); -// if lookahead.peek( syn::Ident ) -// { -// let ident : syn::Ident = input.parse()?; -// // xxx : qqq for Anton : use match here and for all attributes -// if ident == "off" -// { -// input.parse::< syn::Token![ = ] >()?; -// let value : syn::LitBool = input.parse()?; -// off = value.value(); -// } -// else if ident == "on" -// { -// input.parse::< syn::Token![ = ] >()?; -// let value : syn::LitBool = input.parse()?; -// on = value.value(); -// } -// else if ident == "hint" -// { -// input.parse::< syn::Token![ = ] >()?; -// let value : syn::LitBool = input.parse()?; -// hint = value.value; -// } -// else -// { -// return Err( syn::Error::new_spanned( &ident, format!( "Unexpected identifier '{}'. Expected 'on', 'off', or 'hint'. For example: `#[ from( off, hint : true ) ]`", ident ) ) ); -// } -// } -// else -// { -// return Err( syn::Error::new( input.span(), "Unexpected identifier '{}'. Expected 'on', 'off', or 'hint'. For example: `#[ from( off, hint : true ) ]`" ) ); -// } -// -// } -// -// // xxx : move on / off logic into a helper -// -// let mut enabled : Option< bool >; -// -// if on && off -// { -// return Err( syn_err!( input, "`on` and `off` are mutually exclusive .\nIllegal attribute usage : {}", qt!{ #input } ) ) -// // xxx : test -// } -// -// if !on && !off -// { -// enabled = None; -// } -// else if on -// { -// enabled = Some( true ) -// } -// else if off -// { -// enabled = Some( false ) -// } -// -// // Optional comma handling -// if input.peek( syn::Token![,] ) -// { -// input.parse::< syn::Token![,] >()?; -// } -// Ok( Self { enabled, hint } ) -// } -// } +/// +/// Attributes of a field / variant +/// + +pub struct FieldAttributes +{ + pub from : Option< AttributeFrom >, +} + +impl FieldAttributes +{ + + pub fn from_attrs< 'a >( attrs : impl Iterator< Item = &'a syn::Attribute > ) -> Result< Self > + { + let mut from : Option< AttributeFrom > = None; + + for attr in attrs + { + let key_ident = attr.path().get_ident() + .ok_or_else( || syn_err!( attr, "Expects an attribute of format #[ attribute( val ) ], but got:\n {}", qt!{ #attr } ) )?; + let key_str = format!( "{}", key_ident ); + + if attr::is_standard( &key_str ) + { + continue; + } + + // qqq : qqq for Anton : xxx : refactor field_attrs::FieldAttributes::from_attrs to make it similar to this function + match key_str.as_ref() + { + AttributeFrom::KEYWORD => + { + from.replace( AttributeFrom::from_meta( attr )? ); + } + "debug" => + { + } + _ => + { + return Err( syn_err!( attr, "Known field attirbutes are : `from`, `debug`.\nUnknown structure attribute : {}", qt!{ #attr } ) ); + } + } + } + + Ok( FieldAttributes { from } ) + } + +} + + +/// +/// Attribute to hold parameters of forming for a specific field or variant. +/// For example to avoid code From generation for it. +/// +/// `#[ from( off, hint : true ) ]` +/// + +#[ derive( Default ) ] +pub struct AttributeFrom +{ + /// Specifies whether we should generate From implementation for the field. + /// Can be altered using `on` and `off` attributes + pub enabled : Option< bool >, + /// Specifies whether to provide a sketch of generated From or not. + /// Defaults to `false`, which means no hint is provided unless explicitly requested. + pub hint : bool, +} + +impl AttributeFrom +{ + + const KEYWORD : &'static str = "from"; + + pub fn from_meta( attr : &syn::Attribute ) -> Result< Self > + { + match attr.meta + { + syn::Meta::List( ref meta_list ) => + { + return syn::parse2::< AttributeFrom >( meta_list.tokens.clone() ); + }, + syn::Meta::Path( ref _path ) => + { + return Ok( Default::default() ) + }, + _ => return_syn_err!( attr, "Expects an attribute of format #[ from( off ) ] +.\nGot: {}", qt!{ #attr } ), + } + } + +} + +impl syn::parse::Parse for AttributeFrom +{ + fn parse( input : syn::parse::ParseStream< '_ > ) -> syn::Result< Self > + { + let mut off : bool = false; + let mut on : bool = false; + let mut hint = false; + + while !input.is_empty() + { + let lookahead = input.lookahead1(); + if lookahead.peek( syn::Ident ) + { + let ident : syn::Ident = input.parse()?; + // xxx : qqq for Anton : use match here and for all attributes -- done + match ident.to_string().as_str() + { + "off" => + { + input.parse::< syn::Token![ = ] >()?; + let value : syn::LitBool = input.parse()?; + off = value.value(); + }, + "on" => + { + input.parse::< syn::Token![ = ] >()?; + let value : syn::LitBool = input.parse()?; + on = value.value(); + } + "hint" => + { + input.parse::< syn::Token![ = ] >()?; + let value : syn::LitBool = input.parse()?; + hint = value.value; + } + _ => + { + return Err( syn::Error::new_spanned( &ident, format!( "Unexpected identifier '{}'. Expected 'on', 'off', or 'hint'. For example: `#[ from( off, hint : true ) ]`", ident ) ) ); + } + } + } + else + { + return Err( syn::Error::new( input.span(), "Unexpected identifier '{}'. Expected 'on', 'off', or 'hint'. For example: `#[ from( off, hint : true ) ]`" ) ); + } + + } + + // xxx : move on / off logic into a helper + + let mut enabled : Option< bool > = None; + + if on && off + { + // return Err( syn_err!( input, "`on` and `off` are mutually exclusive .\nIllegal attribute usage : {}", qt!{ #input } ) ) + return Err( syn::Error::new( input.span(), "`on` and `off` are mutually exclusive .\nIllegal attribute usage" ) ); + // xxx : test + } + + if !on && !off + { + enabled = None; + } + else if on + { + enabled = Some( true ) + } + else if off + { + enabled = Some( false ) + } + + // Optional comma handling + if input.peek( syn::Token![,] ) + { + input.parse::< syn::Token![,] >()?; + } + Ok( Self { enabled, hint } ) + } +} diff --git a/module/core/former_meta/src/derive_former/field_attrs.rs b/module/core/former_meta/src/derive_former/field_attrs.rs index 3f16d3e2a7..c062d84373 100644 --- a/module/core/former_meta/src/derive_former/field_attrs.rs +++ b/module/core/former_meta/src/derive_former/field_attrs.rs @@ -501,33 +501,36 @@ impl syn::parse::Parse for AttributeSubformEntrySetter let mut setter : Option< bool > = None; let mut hint = false; - // xxx : qqq for Anton : use match here and for all attributes + // xxx : qqq for Anton : use match here and for all attributes -- done while !input.is_empty() { let lookahead = input.lookahead1(); if lookahead.peek( syn::Ident ) { let ident : syn::Ident = input.parse()?; - if ident == "name" - { - input.parse::< syn::Token![ = ] >()?; - name = Some( input.parse()? ); - } - else if ident == "setter" - { - input.parse::< syn::Token![ = ] >()?; - let value : syn::LitBool = input.parse()?; - setter = Some( value.value() ); - } - else if ident == "hint" - { - input.parse::< syn::Token![ = ] >()?; - let value : syn::LitBool = input.parse()?; - hint = value.value; - } - else + match ident.to_string().as_str() { - return Err( syn::Error::new_spanned( &ident, format!( "Unexpected identifier '{}'. Expected 'name', 'setter', or 'definition'. For example: `subform( name = myName, setter = true )`", ident ) ) ); + "name" => + { + input.parse::< syn::Token![ = ] >()?; + name = Some( input.parse()? ); + } + "setter" => + { + input.parse::< syn::Token![ = ] >()?; + let value : syn::LitBool = input.parse()?; + setter = Some( value.value() ); + } + "hint" => + { + input.parse::< syn::Token![ = ] >()?; + let value : syn::LitBool = input.parse()?; + hint = value.value; + } + _ => + { + return Err( syn::Error::new_spanned( &ident, format!( "Unexpected identifier '{}'. Expected 'name', 'setter', or 'definition'. For example: `subform( name = myName, setter = true )`", ident ) ) ); + } } } else diff --git a/module/core/former_meta/src/derive_former/struct_attrs.rs b/module/core/former_meta/src/derive_former/struct_attrs.rs index b43e1cbd57..68771dd609 100644 --- a/module/core/former_meta/src/derive_former/struct_attrs.rs +++ b/module/core/former_meta/src/derive_former/struct_attrs.rs @@ -239,7 +239,7 @@ impl syn::parse::Parse for AttributeMutator let mut custom = false; let mut hint = false; - // xxx : qqq for Anton : use match here and for all attributes + // xxx : qqq for Anton : use match here and for all attributes -- done while !input.is_empty() { let lookahead = input.lookahead1(); @@ -247,19 +247,22 @@ impl syn::parse::Parse for AttributeMutator { let ident : syn::Ident = input.parse()?; input.parse::< syn::Token![=] >()?; - if ident == "custom" + match ident.to_string().as_str() { - let value : syn::LitBool = input.parse()?; - custom = value.value; - } - else if ident == "hint" - { - let value : syn::LitBool = input.parse()?; - hint = value.value; - } - else - { - return Err( syn::Error::new_spanned( &ident, format!( "Unexpected identifier '{}'. Expected 'custom' or 'hint'.", ident ) ) ); + "custom" => + { + let value : syn::LitBool = input.parse()?; + custom = value.value; + } + "hint" => + { + let value : syn::LitBool = input.parse()?; + hint = value.value; + } + _ => + { + return Err( syn::Error::new_spanned( &ident, format!( "Unexpected identifier '{}'. Expected 'custom' or 'hint'.", ident ) ) ); + } } } else