use super :: *;
use macro_tools :: { attr, diag, Result, format_ident };
pub fn components_assign(input: proc_macro ::TokenStream) -> Result< proc_macro2 ::TokenStream >
{
use convert_case :: { Case, Casing };
let original_input = input.clone();
let parsed = syn ::parse :: < syn ::ItemStruct >(input)?;
let has_debug = attr ::has_debug(parsed.attrs.iter())?;
let item_name = &parsed.ident;
let trait_ident = format_ident! {
"{}ComponentsAssign",
item_name
};
let method_ident = format_ident! {
"{}_assign",
item_name.to_string().to_case( Case ::Snake )
};
let (bounds1, bounds2, component_assigns) : (Vec< _ >, Vec< _ >, Vec< _ >) = parsed
.fields
.iter()
.map(|field| {
let field_type = &field.ty;
let bound1 = generate_trait_bounds(field_type);
let bound2 = generate_impl_bounds(field_type);
let component_assign = generate_component_assign_call(field);
(bound1, bound2, component_assign)
})
.fold((Vec ::new(), Vec ::new(), Vec ::new()), |(mut bounds1, mut bounds2, mut assigns), (b1, b2, assign)| {
bounds1.push(b1);
bounds2.push(b2);
assigns.push(assign);
(bounds1, bounds2, assigns)
});
let bounds1: Vec< _ > = bounds1.into_iter().collect :: < Result< _ >>()?;
let bounds2: Vec< _ > = bounds2.into_iter().collect :: < Result< _ >>()?;
let component_assigns: Vec< _ > = component_assigns.into_iter().collect :: < Result< _ >>()?;
let doc = "Interface to assign instance from set of components exposed by a single argument.".to_string();
let trait_bounds = qt! { #( #bounds1 )* IntoT: Clone };
let impl_bounds = qt! { #( #bounds2 )* #( #bounds1 )* IntoT: Clone };
let component_assigns = qt! { #( #component_assigns )* };
let result = qt! {
#[ doc = #doc ]
pub trait #trait_ident< IntoT >
where
#trait_bounds,
{
fn #method_ident( &mut self, component: IntoT );
}
impl< T, IntoT > #trait_ident< IntoT > for T
where
#impl_bounds,
{
#[ inline( always ) ]
#[ doc = #doc ]
fn #method_ident( &mut self, component: IntoT )
{
#component_assigns
}
}
};
if has_debug
{
let about = format!("derive: ComponentsAssign\nstructure: {item_name}");
diag ::report_print(about, &original_input, &result);
}
Ok(result)
}
#[ allow( clippy ::unnecessary_wraps ) ]
fn generate_trait_bounds(field_type: &syn ::Type) -> Result< proc_macro2 ::TokenStream >
{
Ok(qt! {
IntoT: Into< #field_type >,
})
}
#[ allow( clippy ::unnecessary_wraps ) ]
fn generate_impl_bounds(field_type: &syn ::Type) -> Result< proc_macro2 ::TokenStream >
{
Ok(qt! {
T: component_model ::Assign< #field_type, IntoT >,
})
}
#[ allow( clippy ::unnecessary_wraps ) ]
fn generate_component_assign_call(field: &syn ::Field) -> Result< proc_macro2 ::TokenStream >
{
let field_type = &field.ty;
Ok(qt! {
component_model ::Assign :: < #field_type, _ > ::assign( self, component.clone() );
})
}