use macro_tools :: { Result, AttributeComponent, AttributePropertyComponent, AttributePropertyOptionalSingletone, syn, return_syn_err, syn_err, qt, Token, proc_macro2 ::TokenStream };
use component_model_types :: { Assign, OptionExt };
#[ derive( Debug ) ] #[ derive( Default ) ]
pub struct ItemAttributes
{
pub storage_fields: Option< AttributeStorageFields >,
pub mutator: AttributeMutator,
pub perform: Option< AttributePerform >,
pub standalone_constructors: AttributePropertyStandaloneConstructors,
pub debug: AttributePropertyDebug, }
impl ItemAttributes
{
pub fn from_attrs< 'a >(attrs_iter: impl Iterator< Item = &'a syn ::Attribute >) -> Result< Self >
{
let mut result = Self ::default();
for attr in attrs_iter
{
let path = attr.path();
if path.is_ident("former")
{
match &attr.meta
{
syn ::Meta ::List(meta_list) =>
{
let tokens_inside_former = meta_list.tokens.clone();
let parsed_former_attrs = syn ::parse2 :: < ItemAttributes >(tokens_inside_former)?;
result.debug.assign(parsed_former_attrs.debug);
result
.standalone_constructors
.assign(parsed_former_attrs.standalone_constructors);
}
_ => return_syn_err!(attr, "Expected #[ former( ... ) ] to be a list attribute like #[ former( debug ) ]"),
}
} else if path.is_ident(AttributeStorageFields ::KEYWORD)
{
result.assign(AttributeStorageFields ::from_meta(attr)?);
} else if path.is_ident(AttributeMutator ::KEYWORD)
{
result.assign(AttributeMutator ::from_meta(attr)?);
} else if path.is_ident(AttributePerform ::KEYWORD)
{
result.assign(AttributePerform ::from_meta(attr)?);
} else if path.is_ident(AttributePropertyDebug ::KEYWORD)
{
result.debug.assign(AttributePropertyDebug ::from(true));
} else if path.is_ident(AttributePropertyStandaloneConstructors ::KEYWORD)
{
result
.standalone_constructors
.assign(AttributePropertyStandaloneConstructors ::from(true));
}
}
Ok(result)
}
#[ allow( clippy ::unnecessary_wraps ) ]
pub fn performer( &self ) -> Result< (TokenStream, TokenStream, TokenStream) >
{
let mut perform = qt! {
return result;
};
let mut perform_output = qt! { Definition ::Formed };
let mut perform_generics = qt! {};
if let Some(ref attr) = self.perform
{
let signature = &attr.signature;
let generics = &signature.generics;
perform_generics = qt! { #generics };
let perform_ident = &signature.ident;
let output = &signature.output;
if let syn ::ReturnType ::Type(_, boxed_type) = output
{
perform_output = qt! { #boxed_type };
}
perform = qt! {
return result.#perform_ident();
};
}
Ok((perform, perform_output, perform_generics))
}
pub fn storage_fields( &self ) -> &syn ::punctuated ::Punctuated< syn ::Field, syn ::token ::Comma >
{
self.storage_fields.as_ref().map_or_else(
|| &*Box ::leak(Box ::new(syn ::punctuated ::Punctuated ::new())),
|attr| &attr.fields,
)
}
}
impl< IntoT > Assign< AttributeStorageFields, IntoT > for ItemAttributes
where
IntoT: Into< AttributeStorageFields >,
{
#[ inline( always ) ]
fn assign(&mut self, component: IntoT)
{
let component = component.into();
self.storage_fields.option_assign(component);
}
}
impl< IntoT > Assign< AttributeMutator, IntoT > for ItemAttributes
where
IntoT: Into< AttributeMutator >,
{
#[ inline( always ) ]
fn assign(&mut self, component: IntoT)
{
let component = component.into();
self.mutator.assign(component);
}
}
impl< IntoT > Assign< AttributePerform, IntoT > for ItemAttributes
where
IntoT: Into< AttributePerform >,
{
#[ inline( always ) ]
fn assign(&mut self, component: IntoT)
{
let component = component.into();
self.perform.option_assign(component);
}
}
impl< IntoT > Assign< AttributePropertyStandaloneConstructors, IntoT > for ItemAttributes
where
IntoT: Into< AttributePropertyStandaloneConstructors >,
{
#[ inline( always ) ]
fn assign(&mut self, component: IntoT)
{
let component = component.into();
self.standalone_constructors.assign(component);
}
}
impl< IntoT > Assign< AttributePropertyDebug, IntoT > for ItemAttributes
where
IntoT: Into< AttributePropertyDebug >,
{
#[ inline( always ) ]
fn assign(&mut self, component: IntoT)
{
let component = component.into();
self.debug.assign(component);
}
}
#[ derive( Debug, Default ) ]
pub struct AttributeStorageFields
{
pub fields: syn ::punctuated ::Punctuated< syn ::Field, syn ::token ::Comma >,
}
impl AttributeComponent for AttributeStorageFields
{
const KEYWORD: &'static str = "storage_fields";
fn from_meta(attr: &syn ::Attribute) -> Result< Self >
{
match attr.meta
{
syn ::Meta ::List(ref meta_list) => syn ::parse2 :: < AttributeStorageFields >(meta_list.tokens.clone()),
_ => return_syn_err!(
attr,
"Expects an attribute of format #[ storage_fields( a: i32, b: Option< String > ) ]
.\nGot: {}",
qt! { #attr }
),
}
}
}
impl< IntoT > Assign< AttributeStorageFields, IntoT > for AttributeStorageFields
where
IntoT: Into< AttributeStorageFields >,
{
#[ inline( always ) ]
fn assign(&mut self, component: IntoT)
{
let component = component.into();
self.fields = component.fields;
}
}
impl syn ::parse ::Parse for AttributeStorageFields
{
fn parse(input: syn ::parse ::ParseStream< '_ >) -> syn ::Result< Self >
{
let fields: syn ::punctuated ::Punctuated< syn ::Field, syn ::Token![ , ] > =
input.parse_terminated(syn ::Field ::parse_named, Token![ , ])?;
Ok(Self { fields })
}
}
#[ derive( Debug, Default ) ]
pub struct AttributeMutator
{
pub custom: AttributePropertyCustom,
pub debug: AttributePropertyDebug,
}
#[ allow( clippy ::match_wildcard_for_single_variants ) ]
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()),
_ => return_syn_err!(
attr,
"Expects an attribute of format `#[ mutator( custom ) ]`. \nGot: {}",
qt! { #attr }
),
}
}
}
impl< IntoT > Assign< AttributeMutator, IntoT > for AttributeMutator
where
IntoT: Into< AttributeMutator >,
{
#[ inline( always ) ]
fn assign(&mut self, component: IntoT)
{
let component = component.into();
self.custom.assign(component.custom);
self.debug.assign(component.debug);
}
}
impl< IntoT > Assign< AttributePropertyDebug, IntoT > for AttributeMutator
where
IntoT: Into< AttributePropertyDebug >,
{
#[ inline( always ) ]
fn assign(&mut self, component: IntoT)
{
self.debug = component.into();
}
}
impl< IntoT > Assign< AttributePropertyCustom, IntoT > for AttributeMutator
where
IntoT: Into< AttributePropertyCustom >,
{
#[ inline( always ) ]
fn assign(&mut self, component: IntoT)
{
self.custom = component.into();
}
}
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 = format!(
"Known entries of attribute {} are: {}, {}.",
AttributeMutator ::KEYWORD,
AttributePropertyCustom ::KEYWORD,
AttributePropertyDebug ::KEYWORD
);
syn_err!(
ident,
r"Expects an attribute of format '#[ mutator( custom ) ]'
{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 ::from(true)),
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)
}
}
impl syn ::parse ::Parse for ItemAttributes
{
fn parse(input: syn ::parse ::ParseStream< '_ >) -> syn ::Result< Self >
{
let mut result = Self {
storage_fields: None,
mutator: AttributeMutator ::default(),
perform: None,
standalone_constructors: AttributePropertyStandaloneConstructors ::default(),
debug: AttributePropertyDebug ::default(),
};
while !input.is_empty()
{
let key_ident: syn ::Ident = input.parse()?;
let key_str = key_ident.to_string();
match key_str.as_str()
{
AttributePropertyDebug ::KEYWORD => result.debug.assign(AttributePropertyDebug ::from(true)),
AttributePropertyStandaloneConstructors ::KEYWORD => result
.standalone_constructors
.assign(AttributePropertyStandaloneConstructors ::from(true)),
_ => return_syn_err!(
key_ident,
"Unknown key '{}' for #[ former( ... ) ] attribute. Expected 'debug' or 'standalone_constructors'.",
key_str
),
}
if input.peek(syn ::Token![,])
{
input.parse :: < syn ::Token![,] >()?;
} else if !input.is_empty()
{
return Err(input.error("Expected comma between #[ former( ... ) ] arguments or end of arguments."));
}
}
Ok(result)
}
}
#[ derive( Debug ) ]
pub struct AttributePerform
{
pub signature: syn ::Signature,
}
impl AttributeComponent for AttributePerform
{
const KEYWORD: &'static str = "perform";
fn from_meta(attr: &syn ::Attribute) -> Result< Self >
{
match attr.meta
{
syn ::Meta ::List(ref meta_list) => syn ::parse2 :: < AttributePerform >(meta_list.tokens.clone()),
_ => return_syn_err!(
attr,
"Expects an attribute of format #[ perform( fn parse( mut self ) -> Request ) ]
.\nGot: {}",
qt! { #attr }
),
}
}
}
impl syn ::parse ::Parse for AttributePerform
{
fn parse(input: syn ::parse ::ParseStream< '_ >) -> Result< Self >
{
Ok(Self {
signature: input.parse()?,
})
}
}
impl< IntoT > Assign< AttributePerform, IntoT > for AttributePerform
where
IntoT: Into< AttributePerform >,
{
#[ inline( always ) ]
fn assign(&mut self, component: IntoT)
{
let component = component.into();
self.signature = component.signature;
}
}
#[ derive( Debug, Default, Clone, Copy ) ]
pub struct DebugMarker;
impl AttributePropertyComponent for DebugMarker
{
const KEYWORD: &'static str = "debug";
}
pub type AttributePropertyDebug = AttributePropertyOptionalSingletone< DebugMarker >;
#[ derive( Debug, Default, Clone, Copy ) ]
pub struct CustomMarker;
impl AttributePropertyComponent for CustomMarker
{
const KEYWORD: &'static str = "custom";
}
pub type AttributePropertyCustom = AttributePropertyOptionalSingletone< CustomMarker >;
#[ derive( Debug, Default, Clone, Copy ) ]
pub struct StandaloneConstructorsMarker;
impl AttributePropertyComponent for StandaloneConstructorsMarker
{
const KEYWORD: &'static str = "standalone_constructors";
}
pub type AttributePropertyStandaloneConstructors = AttributePropertyOptionalSingletone< StandaloneConstructorsMarker >;