use super :: *;
use macro_tools :: { attr, diag, item_struct, Result, proc_macro2 ::TokenStream };
#[ inline ]
pub fn from_components(input: proc_macro ::TokenStream) -> Result< proc_macro2 ::TokenStream >
{
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 (field_assigns, final_construction) : (Vec< TokenStream >, TokenStream) = match &parsed.fields
{
syn ::Fields ::Named(fields_named) =>
{
let assigns = field_assign_named(fields_named.named.iter());
let names: Vec< _ > = fields_named.named.iter().map(|f| f.ident.as_ref().unwrap()).collect();
let construction = quote! { Self { #( #names, )* } };
(assigns, construction)
}
syn ::Fields ::Unnamed(fields_unnamed) =>
{
let (assigns, temp_names) = field_assign_unnamed(fields_unnamed.unnamed.iter().enumerate());
let construction = quote! { Self ( #( #temp_names, )* ) };
(assigns, construction)
}
syn ::Fields ::Unit =>
{
(vec![], quote! { Self })
}
};
let field_types = item_struct ::field_types(&parsed);
let trait_bounds = trait_bounds(field_types);
let result = qt! {
impl< T > From< T > for #item_name
where
T: Clone,
#( #trait_bounds )*
{
#[ inline( always ) ]
fn from( src: T ) -> Self
{
#( #field_assigns )*
#final_construction }
}
};
if has_debug
{
let about = format!("derive: FromComponents\nstructure: {0}", &parsed.ident);
diag ::report_print(about, &original_input, &result);
}
Ok(result)
}
#[ inline ]
fn trait_bounds< 'a >(field_types: impl macro_tools ::IterTrait< 'a, &'a syn ::Type >) -> Vec< proc_macro2 ::TokenStream >
{
field_types
.map(|field_type| {
qt! {
T: Into< #field_type >,
}
})
.collect()
}
#[ inline ]
fn field_assign_named< 'a >(fields: impl Iterator< Item = &'a syn ::Field >) -> Vec< proc_macro2 ::TokenStream >
{
fields
.map(|field| {
let field_ident = field.ident.as_ref().unwrap(); let field_type = &field.ty;
qt! {
let #field_ident = Into :: < #field_type > ::into( src.clone() );
}
})
.collect()
}
#[ inline ]
fn field_assign_unnamed< 'a >(
fields: impl Iterator< Item = (usize, &'a syn ::Field) >,
) -> (Vec< proc_macro2 ::TokenStream >, Vec< proc_macro2 ::Ident >) {
fields
.map(|(index, field)| {
let temp_var_name = format_ident!("field_{}", index); let field_type = &field.ty;
let assign_snippet = qt! {
let #temp_var_name = Into :: < #field_type > ::into( src.clone() );
};
(assign_snippet, temp_var_name)
})
.unzip() }