use macro_tools ::prelude :: *;
use macro_tools :: { Result, AttributePropertyOptionalSingletone, AttributePropertyComponent, diag, generic_params, ct };
use component_model_types :: { Assign };
pub fn clone_dyn(attr_input: proc_macro ::TokenStream, item_input: proc_macro ::TokenStream) -> Result< proc_macro2 ::TokenStream >
{
let attrs = syn ::parse :: < ItemAttributes >(attr_input)?;
let original_input = item_input.clone();
let mut item_parsed = syn ::parse :: < syn ::ItemTrait >(item_input)?;
let has_debug = attrs.debug.value(false);
let item_name = &item_parsed.ident;
let (_generics_with_defaults, generics_impl, generics_ty, generics_where) = generic_params ::decompose(&item_parsed.generics);
let extra_where_clause: syn ::WhereClause = parse_quote! {
where
Self: clone_dyn ::CloneDyn,
};
if let Some(mut existing_where_clause) = item_parsed.generics.where_clause
{
existing_where_clause.predicates.extend(extra_where_clause.predicates);
item_parsed.generics.where_clause = Some(existing_where_clause);
} else {
item_parsed.generics.where_clause = Some(extra_where_clause);
}
let result = qt! {
#item_parsed
#[ allow( non_local_definitions ) ]
impl < 'c, #generics_impl > Clone
for Box< dyn #item_name< #generics_ty > + 'c >
where
#generics_where
{
#[ inline ]
fn clone( &self ) -> Self
{
clone_dyn ::clone_into_box( &**self )
}
}
#[ allow( non_local_definitions ) ]
impl < 'c, #generics_impl > Clone
for Box< dyn #item_name< #generics_ty > + Send + 'c >
where
#generics_where
{
#[ inline ]
fn clone( &self ) -> Self
{
clone_dyn ::clone_into_box( &**self )
}
}
#[ allow( non_local_definitions ) ]
impl < 'c, #generics_impl > Clone
for Box< dyn #item_name< #generics_ty > + Sync + 'c >
where
#generics_where
{
#[ inline ]
fn clone( &self ) -> Self
{
clone_dyn ::clone_into_box( &**self )
}
}
#[ allow( non_local_definitions ) ]
impl < 'c, #generics_impl > Clone
for Box< dyn #item_name< #generics_ty > + Send + Sync + 'c >
where
#generics_where
{
#[ inline ]
fn clone( &self ) -> Self
{
clone_dyn ::clone_into_box( &**self )
}
}
};
if has_debug
{
let about = format!("macro: CloneDyn\ntrait: {item_name}");
diag ::report_print(about, &original_input, &result);
}
Ok(result)
}
impl syn ::parse ::Parse for ItemAttributes
{
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 properties of attribute `clone_dyn` are: ",
AttributePropertyDebug ::KEYWORD,
".",
);
syn_err!(
ident,
r"Expects an attribute of format '#[ clone_dyn( {} ) ]'
{known}
But got: '{}'
",
AttributePropertyDebug ::KEYWORD,
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()
{
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)
}
}
#[ derive( Debug, Default ) ]
pub struct ItemAttributes
{
pub debug: AttributePropertyDebug,
}
impl< IntoT > Assign< AttributePropertyDebug, IntoT > for ItemAttributes
where
IntoT: Into< AttributePropertyDebug >,
{
#[ inline( always ) ]
fn assign(&mut self, prop: IntoT)
{
self.debug = prop.into();
}
}
#[ derive( Debug, Default, Clone, Copy ) ]
pub struct AttributePropertyDebugMarker;
impl AttributePropertyComponent for AttributePropertyDebugMarker
{
const KEYWORD: &'static str = "debug";
}
pub type AttributePropertyDebug = AttributePropertyOptionalSingletone< AttributePropertyDebugMarker >;