#[ cfg( not( all( feature = "enabled", feature = "attr_prop", feature = "ct", feature = "components" ) ) ) ]
fn main()
{
println!( "This example requires the 'enabled', 'attr_prop', 'ct', and 'components' features to be enabled." );
println!( "Try running with: cargo run --example macro_tools_attr_prop --all-features" );
}
#[ cfg( all( feature = "enabled", feature = "attr_prop", feature = "ct", feature = "components" ) ) ]
use macro_tools ::
{
ct, syn_err, return_syn_err, qt, Result, AttributeComponent, AttributePropertyComponent, AttributePropertyBoolean,
AttributePropertySingletone, Assign,
};
#[ cfg( all( feature = "enabled", feature = "attr_prop", feature = "ct", feature = "components" ) ) ]
#[ derive( Debug, Default ) ]
pub struct ItemAttributes
{
pub mutator: AttributeMutator,
}
#[ cfg( all( feature = "enabled", feature = "attr_prop", feature = "ct", feature = "components" ) ) ]
impl ItemAttributes
{
pub fn from_attrs< 'a >(attrs: impl Iterator< Item = &'a syn ::Attribute >) -> Result< Self >
{
let mut result = Self ::default();
let error = |attr: &syn ::Attribute| -> syn ::Error {
let known_attributes = ct ::str ::format!("Known attributes are: {}, {}.", "debug", AttributeMutator ::KEYWORD,);
syn_err!(
attr,
"Expects an attribute of format '#[ attribute( key1 = val1, key2 = val2 ) ]'\n {known_attributes}\n But got: '{}'",
qt! { #attr }
)
};
for attr in attrs
{
let key_ident = attr.path().get_ident().ok_or_else( || error( attr ) )?;
let key_str = format!( "{key_ident}" );
if < str as core ::convert ::AsRef< str > >::as_ref( &key_str ) == AttributeMutator ::KEYWORD
{
result.assign( AttributeMutator ::from_meta( attr )? );
}
else
{
}
}
Ok( result )
}
}
#[ cfg( all( feature = "enabled", feature = "attr_prop", feature = "ct", feature = "components" ) ) ]
#[ derive( Debug, Default, Clone, Copy ) ]
pub struct AttributePropertyDebugMarker;
#[ cfg( all( feature = "enabled", feature = "attr_prop", feature = "ct", feature = "components" ) ) ]
impl AttributePropertyComponent for AttributePropertyDebugMarker
{
const KEYWORD: &'static str = "debug";
}
#[ cfg( all( feature = "enabled", feature = "attr_prop", feature = "ct", feature = "components" ) ) ]
pub type AttributePropertyDebug = AttributePropertySingletone< AttributePropertyDebugMarker >;
#[ cfg( all( feature = "enabled", feature = "attr_prop", feature = "ct", feature = "components" ) ) ]
#[ derive( Debug, Default, Clone, Copy ) ]
pub struct AttributePropertyCustomMarker;
#[ cfg( all( feature = "enabled", feature = "attr_prop", feature = "ct", feature = "components" ) ) ]
impl AttributePropertyComponent for AttributePropertyCustomMarker
{
const KEYWORD: &'static str = "custom";
}
#[ cfg( all( feature = "enabled", feature = "attr_prop", feature = "ct", feature = "components" ) ) ]
pub type AttributePropertyCustom = AttributePropertyBoolean< AttributePropertyCustomMarker >;
#[ cfg( all( feature = "enabled", feature = "attr_prop", feature = "ct", feature = "components" ) ) ]
#[ derive( Debug, Default ) ]
pub struct AttributeMutator
{
pub custom: AttributePropertyCustom,
pub debug: AttributePropertyDebug,
}
#[ cfg( all( feature = "enabled", feature = "attr_prop", feature = "ct", feature = "components" ) ) ]
impl AttributeComponent for AttributeMutator
{
const KEYWORD: &'static str = "mutator";
fn from_meta(attr: &syn ::Attribute) -> Result< Self >
{
match attr.meta
{
syn ::Meta ::List(ref meta_list) => syn ::parse2 :: < AttributeMutator >(meta_list.tokens.clone()),
syn ::Meta ::Path(ref _path) => Ok(AttributeMutator ::default()),
syn ::Meta ::NameValue(_) => return_syn_err!(
attr,
"Expects an attribute of format `#[ mutator( custom = true ) ]`. \nGot: {}",
format!("{}", qt! { #attr }),
),
}
}
}
#[ cfg( all( feature = "enabled", feature = "attr_prop", feature = "ct", feature = "components" ) ) ]
impl< IntoT > Assign< AttributeMutator, IntoT > for ItemAttributes
where
IntoT: Into< AttributeMutator >,
{
#[ inline( always ) ]
fn assign(&mut self, component: IntoT)
{
self.mutator = component.into();
}
}
#[ cfg( all( feature = "enabled", feature = "attr_prop", feature = "ct", feature = "components" ) ) ]
impl< IntoT > Assign< AttributePropertyDebug, IntoT > for AttributeMutator
where
IntoT: Into< AttributePropertyDebug >,
{
#[ inline( always ) ]
fn assign(&mut self, component: IntoT)
{
self.debug = component.into();
}
}
#[ cfg( all( feature = "enabled", feature = "attr_prop", feature = "ct", feature = "components" ) ) ]
impl< IntoT > Assign< AttributePropertyCustom, IntoT > for AttributeMutator
where
IntoT: Into< AttributePropertyCustom >,
{
#[ inline( always ) ]
fn assign(&mut self, component: IntoT)
{
self.custom = component.into();
}
}
#[ cfg( all( feature = "enabled", feature = "attr_prop", feature = "ct", feature = "components" ) ) ]
impl syn ::parse ::Parse for AttributeMutator
{
fn parse( input : syn ::parse ::ParseStream< '_ > ) -> syn ::Result< Self >
{
let mut result = Self ::default();
let error = | ident : &syn ::Ident | -> syn ::Error
{
let known = ct ::str ::format!
(
"Known entries of attribute {} are: {}, {}.",
AttributeMutator ::KEYWORD,
AttributePropertyCustom ::KEYWORD,
AttributePropertyDebug ::KEYWORD,
);
syn_err!
(
ident,
r"Expects an attribute of format '#[ mutator( custom = false ) ]'
{known}
But got: '{}'
",
qt! { #ident }
)
};
while !input.is_empty()
{
let lookahead = input.lookahead1();
if lookahead.peek( syn ::Ident )
{
let ident : syn ::Ident = input.parse()?;
match ident.to_string().as_str()
{
AttributePropertyCustom ::KEYWORD => result.assign( AttributePropertyCustom ::parse( input )? ),
AttributePropertyDebug ::KEYWORD => result.assign( AttributePropertyDebug ::from( true ) ),
_ => return Err( error( &ident ) ),
}
}
else
{
return Err( lookahead.error() );
}
if input.peek( syn ::Token![ , ] )
{
input.parse ::< syn ::Token![ , ] >()?;
}
}
Ok( result )
}
}
#[ cfg( all( feature = "enabled", feature = "attr_prop", feature = "ct", feature = "components" ) ) ]
fn main()
{
println!( "=== Attribute Properties Example ===" );
println!();
let input: syn ::Attribute = syn ::parse_quote!( #[ mutator( custom = true, debug ) ] );
match ItemAttributes ::from_attrs(core ::iter ::once(&input))
{
Ok(attrs) =>
{
println!( "Successfully parsed attribute: {attrs:#?}" );
println!( "Custom property: {}", attrs.mutator.custom.internal() );
println!( "Debug property: {}", attrs.mutator.debug.internal() );
}
Err(e) =>
{
println!( "Error parsing attribute: {e}" );
}
}
println!();
println!( "=== End of Example ===" );
}
#[ cfg( test ) ]
mod test
{
use super :: *;
#[ test ]
fn test_attribute_parsing_and_properties()
{
let input: syn ::Attribute = syn ::parse_quote!( #[ mutator( custom = true ) ] );
let attrs: ItemAttributes = ItemAttributes ::from_attrs(core ::iter ::once(&input)).unwrap();
println!("{attrs:?}");
let attr: AttributePropertyBoolean< AttributePropertyDebugMarker > = AttributePropertyBoolean ::default();
assert!(!attr.internal());
let attr: AttributePropertyBoolean< AttributePropertyDebugMarker > = true.into();
assert!(attr.internal());
let attr: AttributePropertyBoolean< AttributePropertyDebugMarker > = false.into();
assert!(!attr.internal());
}
}