use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use syn::Type;
use crate::classify::fields::FieldKind;
use crate::codegen::inner_init::gen_inner_init;
use crate::codegen::intercept;
use crate::codegen::lifecycle::{gen_lifecycle_overrides, LifecycleOverrides};
use crate::codegen::CodeGenContext;
pub fn gen_component_impl(ctx: &CodeGenContext) -> TokenStream2 {
let struct_name = &ctx.struct_name;
let scope_const = ctx.comp_attr.scope_tokens();
let is_config_component = ctx.comp_attr.is_config_component();
let dep_types: Vec<&Type> = ctx
.inject_fields
.iter()
.map(|(_, ty)| ty)
.collect();
let dep_count = dep_types.len();
let deps_type = if dep_count == 0 {
quote! { () }
} else if dep_count == 1 {
let ty = &dep_types[0];
quote! { (std::sync::Arc<#ty>,) }
} else {
quote! { (#(std::sync::Arc<#dep_types>),*) }
};
let build_fields: Vec<TokenStream2> = ctx
.fields_info
.iter()
.map(|(fname, kind)| match kind {
FieldKind::Skip => quote! { #fname: Default::default() },
FieldKind::Optional { .. } => quote! { #fname: None },
FieldKind::Inject { .. } => {
let idx = ctx
.inject_fields
.iter()
.position(|(name, _)| name == fname)
.unwrap();
let idx_lit = proc_macro2::Literal::usize_unsuffixed(idx);
quote! { #fname: deps.#idx_lit.clone() }
}
FieldKind::TraitInject { .. } => {
quote! { #fname: None }
}
FieldKind::TraitInjectRequired { .. } => {
quote! {
#fname: unsafe { ::core::mem::zeroed() }
}
}
FieldKind::TraitInjectList { .. } => {
quote! { #fname: ::std::vec::Vec::new() }
}
FieldKind::Custom { expr } => quote! { #fname: #expr },
})
.collect();
let (deps_type_final, build_body) = if is_config_component {
let build_body = quote! {
panic!("[di] 配置组件 {} 的 build() 不应被直接调用", stringify!(#struct_name))
};
(quote! { () }, build_body)
} else {
let build_body = quote! {
Self {
#( #build_fields ),*
}
};
(deps_type, build_body)
};
let inner_init_impl = gen_inner_init(ctx);
let init_sort_override = ctx.comp_attr.init_sort.as_ref().map(|val| {
quote! {
#[inline]
fn init_sort() -> i32 { #val }
}
});
let LifecycleOverrides {
app_init: lifecycle_app_init,
app_async_init,
app_async_run,
shutdown,
} = gen_lifecycle_overrides(ctx);
let interceptor_init = intercept::gen_interceptor_init_override(ctx);
let has_interceptors = !ctx.comp_attr.interceptors.is_empty();
let app_init_final = if has_interceptors {
interceptor_init
} else {
lifecycle_app_init
};
quote! {
impl ::tx_di_core::Component for #struct_name {
type Deps = #deps_type_final;
fn build(deps: Self::Deps) -> Self {
#build_body
}
const SCOPE: ::tx_di_core::Scope = #scope_const;
#inner_init_impl
#app_init_final
#app_async_init
#app_async_run
#shutdown
#init_sort_override
}
}
}