use proc_macro2::TokenStream as TokenStream2;
use quote::{format_ident, quote};
use crate::codegen::CodeGenContext;
use crate::name_utils::camel_to_screaming_snake;
pub fn gen_meta_entry(ctx: &CodeGenContext, factory_fn: TokenStream2) -> TokenStream2 {
let struct_name = &ctx.struct_name;
let vis = &ctx.vis;
let scope_const = ctx.comp_attr.scope_tokens();
let is_config_component = ctx.comp_attr.is_config_component();
let meta_ident = format_ident!(
"__DI_META_{}",
camel_to_screaming_snake(&struct_name.to_string())
);
let dep_type_id_fns: Vec<TokenStream2> = if is_config_component {
Vec::new()
} else {
let mut fns: Vec<TokenStream2> = ctx
.inject_fields
.iter()
.map(|(_, ty)| quote! { || std::any::TypeId::of::<#ty>() })
.collect();
let trait_fns: Vec<TokenStream2> = ctx
.trait_inject_fields
.iter()
.chain(ctx.required_trait_fields.iter())
.chain(ctx.list_trait_fields.iter())
.map(|(_, ty)| quote! { || std::any::TypeId::of::<#ty>() })
.collect();
fns.extend(trait_fns);
fns
};
let (impl_traits_arr, trait_impls_arr) = if let Some(trait_ty) = &ctx.comp_attr.as_trait {
(
vec![quote! { || std::any::TypeId::of::<#trait_ty>() }],
vec![quote! {
::tx_di_core::TraitImplEntry {
concrete_tid: || std::any::TypeId::of::<#struct_name>(),
upcast: |concrete: std::sync::Arc<dyn std::any::Any + Send + Sync>| {
let instance = concrete.downcast::<#struct_name>()
.expect("[di] trait upcast: 具体类型 downcast 失败");
let as_trait: std::sync::Arc<#trait_ty> = instance;
std::sync::Arc::new(as_trait) as std::sync::Arc<dyn std::any::Any + Send + Sync>
},
}
}],
)
} else {
(vec![], vec![])
};
quote! {
#[::tx_di_core::linkme::distributed_slice(::tx_di_core::COMPONENT_REGISTRY)]
#[linkme(crate = ::tx_di_core::linkme)]
#[allow(non_upper_case_globals)]
#vis static #meta_ident: ::tx_di_core::ComponentMeta = ::tx_di_core::ComponentMeta {
type_id: || std::any::TypeId::of::<#struct_name>(),
name: std::stringify!(#struct_name),
dep_type_ids: &[ #( #dep_type_id_fns ),* ],
factory: ( #factory_fn ) as fn(&::tx_di_core::Store) -> Box<dyn std::any::Any + Send + Sync>,
scope: #scope_const,
impl_traits: &[ #( #impl_traits_arr ),* ],
trait_impls: &[ #( #trait_impls_arr ),* ],
init_sort_fn: <#struct_name as ::tx_di_core::Component>::init_sort,
init_fn: |app: &std::sync::Arc<::tx_di_core::App>| -> ::tx_di_core::RIE<()> {
<#struct_name as ::tx_di_core::Component>::init(app)
},
async_init_fn: |app: &std::sync::Arc<::tx_di_core::App>| -> ::tx_di_core::BoxFuture<::tx_di_core::RIE<()>> {
<#struct_name as ::tx_di_core::Component>::async_init(app)
},
async_run_fn: |app: &std::sync::Arc<::tx_di_core::App>, token: ::tx_di_core::CancellationToken| -> ::tx_di_core::BoxFuture<::tx_di_core::RIE<()>> {
<#struct_name as ::tx_di_core::Component>::async_run(app, token)
},
shutdown_fn: |store: &::tx_di_core::Store| {
if let Some(arc) = store.try_inject::<#struct_name>() {
use std::ops::Deref;
arc.deref().shutdown();
}
},
};
}
}