use syn::{Expr, Ident, ItemStruct, Result as SynResult, Type};
use crate::attr::field_attr::{extract_inject_expr, has_skip_attr};
use crate::type_utils::{is_arc_dyn_trait, is_option_type, is_plain_arc_dyn_trait, is_vec_arc_dyn_trait};
#[derive(Clone)]
pub enum FieldKind {
Inject { ty: Type },
TraitInject { ty: Type },
TraitInjectRequired { ty: Type },
TraitInjectList { ty: Type },
Custom { expr: Expr },
Optional { _ty: Type },
Skip,
}
pub fn classify_fields(input: &ItemStruct) -> SynResult<Vec<(Ident, FieldKind)>> {
let mut fields_info: Vec<(Ident, FieldKind)> = Vec::new();
for field in &input.fields {
let ident = field
.ident
.as_ref()
.ok_or_else(|| syn::Error::new_spanned(&field.ty, "#[tx_cst] 只支持具名字段"))?;
let inject_expr = extract_inject_expr(&field.attrs)?;
let kind = if has_skip_attr(&field.attrs) {
FieldKind::Skip
} else if is_plain_arc_dyn_trait(&field.ty) {
FieldKind::TraitInjectRequired { ty: field.ty.clone() }
} else if is_vec_arc_dyn_trait(&field.ty) {
FieldKind::TraitInjectList { ty: field.ty.clone() }
} else if is_arc_dyn_trait(&field.ty) {
FieldKind::TraitInject { ty: field.ty.clone() }
} else if is_option_type(&field.ty) {
FieldKind::Optional { _ty: field.ty.clone() }
} else if let Some(expr) = inject_expr {
FieldKind::Custom { expr }
} else {
FieldKind::Inject { ty: field.ty.clone() }
};
fields_info.push((ident.clone(), kind));
}
Ok(fields_info)
}