tx-di-macros 0.4.0

宏支持 di-core
Documentation
# tx-di-macros


proc-macro crate,为 `tx-di-core` DI 框架提供 `#[derive(Component)]` 宏。

## 模块结构


```
tx-di-macros/src/
├── lib.rs              # proc_macro 入口 + 文档
├── attr/
│   ├── mod.rs          # re-export
│   ├── comp_attr.rs    # #[component(...)] 属性解析 + CompAttr / ScopeAttr 定义
│   └── field_attr.rs   # #[tx_cst(...)] 字段属性解析
├── classify/
│   ├── mod.rs
│   └── fields.rs       # FieldKind 枚举 + classify_fields 函数
├── codegen/
│   ├── mod.rs          # CodeGenContext + derive_component_impl 编排
│   ├── component_impl.rs   # 生成 impl Component for T(含 intercept init 装配)
│   ├── factory.rs          # 生成 factory 闭包
│   ├── inner_init.rs       # 生成 inner_init 方法
│   ├── lifecycle.rs        # 生命周期覆写(init/app_init/app_async_init/app_async_run/shutdown)
│   ├── intercept.rs        # 生成 AOP 拦截器链 init 覆写
│   └── meta_entry.rs       # 生成 linkme ComponentMeta 注册条目
├── intercept_macro.rs  # #[intercept] 方法属性宏
├── type_utils.rs       # 类型检测工具(Arc/Option/Arc<dyn Trait>)
└── name_utils.rs       # 命名转换工具(驼峰 ↔ 蛇形)
```

### 数据流


```
属性解析 ──→ 字段分类 ──→ CodeGenContext ──→ 代码生成 ──→ 组装输出
(comp_attr)  (fields)                     (4个子模块)    (quote!)
```

### 各模块职责


| 模块 | 职责 | 对外 API |
|------|------|----------|
| `attr::comp_attr` | 解析 `#[component(...)]` 为 `CompAttr` | `parse_component_attr_from_attributes`, `CompAttr`, `ScopeAttr` |
| `attr::field_attr` | 解析 `#[tx_cst(expr)]` 和 `#[tx_cst(skip)]` | `extract_inject_expr`, `has_skip_attr` |
| `classify::fields` | 按类型形态对字段分类 | `classify_fields`, `FieldKind` |
| `codegen` | 编排代码生成 + 持有 `CodeGenContext` | `derive_component`(proc_macro 入口) |
| `codegen::component_impl` | 生成 `impl Component` | `gen_component_impl` |
| `codegen::factory` | 生成 factory 闭包 | `gen_factory_fn` |
| `codegen::inner_init` | 生成 `inner_init` 方法 | `gen_inner_init` |
| `codegen::lifecycle` | 生成生命周期覆写(init / app_init / app_async_init / app_async_run / shutdown) | `gen_lifecycle_overrides` |
| `codegen::intercept` | 生成 AOP 拦截器链 `init` 覆写 | `gen_interceptor_init_override` |
| `codegen::meta_entry` | 生成 `linkme` 注册条目 | `gen_meta_entry` |
| `intercept_macro` | 提供 `#[intercept]` 方法属性宏 | `intercept_impl` |
| `type_utils` | 类型检测工具函数 | `strip_arc_type`, `is_option_type`, `is_arc_dyn_trait`, `is_plain_arc_dyn_trait`, `extract_trait_from_arc`, `extract_trait_from_option_arc` |
| `name_utils` | 命名转换工具函数 | `camel_to_snake`, `camel_to_screaming_snake` |

---

## 使用方法


### 1. 基本使用


```rust
use tx_di_core::Component;

#[derive(Component)]

pub struct UserService {
    repo: Arc<UserRepo>,
    config: Arc<AppConfig>,
}
```

字段 `repo: Arc<UserRepo>` 会自动解析为 `UserRepo` 类型的组件依赖,从容器中注入。

### 2. 作用域


```rust
// 原型作用域:每次注入都创建新实例
#[derive(Component)]

#[component(scope = Prototype)]

pub struct RequestContext {
    request_id: String,
}
```

默认作用域为 `Singleton`(单例)。支持 `Singleton` 和 `Prototype` 两种。

### 3. 生命周期回调


每个生命周期都通过一个 `#[component(...)]` 标志和一个自定义函数实现:

| `#[component(...)]` | 回调函数签名 | 覆写 trait 方法 | 阶段 |
|---|---|---|---|
| `init` | `fn init(&mut self, store: &Store) -> RIE<()>` | `inner_init` | build 后 |
| `app_init` | `fn app_init(comp: Arc<Self>, app: &Arc<App>) -> RIE<()>` | `init` | 同步初始化 |
| `app_async_init` | `fn app_async_init(comp: Arc<Self>, app: &Arc<App>) -> BoxFuture<RIE<()>>` | `async_init` | 异步初始化 |
| `app_async_run` | `fn app_async_run(comp: Arc<Self>, app: &Arc<App>, token: CancellationToken) -> BoxFuture<RIE<()>>` | `async_run` | 后台运行 |
| `shutdown` | `fn shutdown(&self)` | `shutdown` | 优雅关闭 |

```rust
use tx_di_core::{Component, App, Store, RIE, BoxFuture, CancellationToken};
use std::sync::Arc;

#[derive(Component)]

#[component(init, app_init, app_async_run, shutdown)]

pub struct DatabaseService {
    pool: Arc<DbPool>,
}

fn init(&mut self, store: &Store) -> RIE<()> {
    Ok(())
}

fn app_init(comp: Arc<Self>, app: &Arc<App>) -> RIE<()> {
    println!("connected: {}", comp.pool.is_connected());
    Ok(())
}

fn app_async_run(comp: Arc<Self>, app: &Arc<App>, token: CancellationToken) -> BoxFuture<RIE<()>> {
    Box::pin(async move {
        loop { tokio::select! { _ = token.cancelled() => break, } }
        Ok(())
    })
}

fn shutdown(&self) {
    self.pool.close();
}
```

### 4. 配置组件


### 5. Trait 实现注册


```rust
#[derive(Component)]

#[component(as_trait = dyn UserRepository)]

pub struct UserRepoImpl {
    db: Arc<DbPool>,
}
```

通过 trait object 按接口注入:

```rust
#[derive(Component)]

pub struct UserService {
    // Arc<dyn Trait> — 必选 trait 注入
    repo: Arc<dyn UserRepository>,

    // Option<Arc<dyn Trait>> — 可选 trait 注入
    cache: Option<Arc<dyn CacheProvider>>,
}
```

### 6. 生命周期回调实现示例


回调**函数名与 `#[component(...)]` 标志保持一致**(如 `init` 标志对应 `fn init`,`app_init` 对应 `fn app_init`)。
宏生成的覆写方法使用 `self::` 前缀调用回调,即使 `init` / `shutdown` 与 trait 方法同名也不会冲突。

```rust
#[derive(Component)]

#[component(init)]

pub struct DatabaseService {
    pool: Arc<DbPool>,
}

// 对应 #[component(init)]:覆写 inner_init,build 完成后、正式使用前调用
fn init(&mut self, store: &Store) -> RIE<()> {
    // 自定义初始化逻辑
    Ok(())
}
```

> 注意:这里的 `fn init` 覆写的是 `inner_init` 而非 trait 的 `init`/`init(app)`。`shutdown` 回调则直接用 `&self` 作为接收器。

### 7. 初始化排序


```rust
use tx_di_core::Component;

#[derive(Component)]

#[component(init_sort = -2147483648)] // 最小整数 → 最先初始化

pub struct DatabaseMigrator {
    db: Arc<DbPool>,
}
```

默认排序值为 `10000`。值越小越先执行。通常核心基础设施使用负值。

### 7. 字段级自定义


```rust
#[derive(Component)]

pub struct Logger {
    // #[tx_cst(expr)] — 用表达式赋值,不从 DI 容器注入
    #[tx_cst("info".to_string())]
    level: String,

    // #[tx_cst(skip)] — 跳过注入,使用 Default::default()
    #[tx_cst(skip)]
    buffer: Vec<String>,

    // Option<T> — 注入时不赋值,保持 None
    fallback: Option<Arc<FallbackLogger>>,
}
```

### 8. 依赖注入规则总结


| 字段类型 | 注入行为 |
|----------|----------|
| `Arc<T>` | 普通组件注入,从容器获取 `T` |
| `Arc<dyn Trait>` | 必选 trait 注入,`inner_init` 中填充 |
| `Option<Arc<dyn Trait>>` | 可选 trait 注入,找不到时保持 `None` |
| `Option<T>` | 可选普通依赖,保持 `None` |
| `#[tx_cst(expr)]` | 表达式赋值 |
| `#[tx_cst(skip)]` | 跳过,使用 `Default::default()` |

---

## 开发指南


### 添加新的 `#[component(...)]` 参数


1. 在 `attr/comp_attr.rs` 的 `CompAttr` 结构体添加字段
2. 在 `CompAttrArgs` 添加对应字段
3. 在 `parse()` 方法中添加解析分支
4. 在 `codegen/` 相应子模块中使用新字段生成代码

### 添加新的字段注入类型


1. 在 `classify/fields.rs` 的 `FieldKind` 添加变体
2. 在 `classify_fields()` 中添加匹配规则
3. 在 `codegen/component_impl.rs` 的 `build_fields` 映射中添加处理
4. 如有需要,在 `codegen/inner_init.rs` 或 `codegen/meta_entry.rs` 中添加相应处理

### 测试


```bash
# 运行全部测试

cargo test -p tx-di-core

# 仅编译宏(快速检查)

cargo build -p tx-di-macros
```

核心测试位于 `tx-di-core/tests/test_component.rs`,覆盖宏的各条代码生成路径。