# Macros
`rs-netty-macros` 提供 `#[handler]`。主 crate 默认 feature 包含 `macros`,因此通常可以直接:
```rust
use rs_netty::handler;
```
## What It Generates
`#[handler(TypeName)]` 把一个 async function 适配成 `Handler<I>` 和 `DatagramHandler<I>` 两个 impl。用户仍然显式声明 handler struct,宏只生成样板代码。
一进一出:
```rust
struct Echo;
#[handler(Echo)]
async fn echo(msg: String) -> rs_netty::Result<String> {
Ok(msg)
}
```
大致等价于:
```rust
impl rs_netty::Handler<String> for Echo {
type Write = String;
async fn read(
&mut self,
ctx: &mut rs_netty::Context<Self::Write>,
msg: String,
) -> rs_netty::Result<()> {
let msg = echo(msg).await?;
ctx.write_and_flush(msg).await
}
}
```
宏同时生成 `DatagramHandler<String>`,方法体使用 `DatagramContext::write_and_flush`。
## Consume-Only Handler
如果函数返回 `Result<()>`,宏无法从返回值推导 `type Write`,必须写 `write = Type`:
```rust
struct PrintResponse;
#[handler(PrintResponse, write = String)]
async fn print_response(msg: String) -> rs_netty::Result<()> {
println!("server -> {msg}");
Ok(())
}
```
这里 `write = String` 的意思是这个 handler 所在连接仍然可以从外部 channel 写入 `String`。
## Handler State
需要访问 handler 字段时,把 `&mut HandlerType` 放在第一个参数:
```rust
struct PrintResponse {
response_tx: Option<tokio::sync::oneshot::Sender<()>>,
}
#[handler(PrintResponse, write = Request)]
async fn print_response(handler: &mut PrintResponse, res: Response) -> rs_netty::Result<()> {
if let Some(tx) = handler.response_tx.take() {
let _ = tx.send(());
}
println!("server -> {}", res.echoed);
Ok(())
}
```
这正是 `examples/tcp_json_line_echo.rs` 使用的模式。
## Limits
宏要求:
- 被标注的函数必须是 `async fn`。
- 函数必须返回 `Result<T>`。
- 参数最多是 `(&mut HandlerType, msg)` 或 `(msg)`。
- `write = Type` 只允许用于返回 `Result<()>` 的函数。
需要直接操作 `Context`/`DatagramContext`、多次写入、手动 flush、关闭连接、拿 `channel()` 或分支复杂时,写手动 impl。