rs-netty 1.1.0

A Tokio-native typed TCP/UDP pipeline framework inspired by Netty.
Documentation
# Macros

`rs-netty-macros` provides `#[handler]`. The main crate's default features include `macros`, so in most cases you can write:

```rust
use rs_netty::handler;
```

## What It Generates

`#[handler(TypeName)]` adapts one async function into both `Handler<I>` and `DatagramHandler<I>` impls. The user still declares the handler struct explicitly; the macro only generates repetitive implementation code.

Request-to-response handler:

```rust
struct Echo;

#[handler(Echo)]
async fn echo(msg: String) -> rs_netty::Result<String> {
    Ok(msg)
}
```

This is roughly equivalent to:

```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
    }
}
```

The macro also generates `DatagramHandler<String>` with `DatagramContext::write_and_flush`.

## Consume-Only Handler

If the function returns `Result<()>`, the macro cannot infer `type Write` from the return type. You must specify `write = Type`:

```rust
struct PrintResponse;

#[handler(PrintResponse, write = String)]
async fn print_response(msg: String) -> rs_netty::Result<()> {
    println!("server -> {msg}");
    Ok(())
}
```

Here `write = String` means the connection can still write `String` values from an external channel.

## Handler State

To access handler fields, put `&mut HandlerType` as the first argument:

```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(())
}
```

This is the pattern used by `examples/tcp_json_line_echo.rs`.

## Limits

The macro requires:

- the annotated function must be `async fn`.
- the function must return `Result<T>`.
- arguments must be either `(&mut HandlerType, msg)` or `(msg)`.
- `write = Type` is allowed only for functions returning `Result<()>`.

Use a manual impl when you need direct `Context`/`DatagramContext` access, multiple writes, manual flushes, connection close, `channel()`, or more complex branching.