rs-netty 1.1.0

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

rs-netty has five stage traits. They live in `src/traits.rs`, and `trait-variant` generates the public `Send` variants used on the main path.

## Inbound

`Inbound<I>` is an inbound transformation stage after decoding and before the final handler:

```rust
struct Trim;

impl Inbound<String> for Trim {
    type Out = String;

    async fn read(
        &mut self,
        _ctx: &mut rs_netty::InboundContext,
        msg: String,
    ) -> rs_netty::Result<rs_netty::Flow<Self::Out>> {
        Ok(rs_netty::Flow::Next(msg.trim().to_string()))
    }
}
```

`InboundContext` exposes `id()`, `peer_addr()`, and `local_addr()`. It does not allow writes.

## Business

`Business<I>` is an application-level transformation stage between inbound stages and the final handler. It has the same type shape as `Inbound`, but the method is `handle` and the context is `BusinessContext`. Once the builder enters the business phase, it can add more business stages or the final handler, but cannot go back to inbound stages.

## Handler

`Handler<I>` is the end of the TCP inbound side:

```rust
impl Handler<Request> for Router {
    type Write = Response;

    async fn read(&mut self, ctx: &mut Context<Self::Write>, req: Request) -> Result<()> {
        ctx.write_and_flush(Response { body: req.body }).await
    }
}
```

`type Write` is the application type this handler can write to the outbound side. Outbound stages start from this type and eventually produce a value the codec can encode.

`Context<W>` provides:

- identity: `id`, `peer_addr`, `local_addr`
- `channel()`: a cloneable external channel
- `stats()`: `ConnectionStats` when stats are enabled
- `write`, `flush`, `write_and_flush`
- `close`

## DatagramHandler

`DatagramHandler<I>` is the end of the UDP inbound side. It uses `DatagramContext<W>`, which supports `write`, `write_to`, `flush`, `write_and_flush`, `write_to_and_flush`, and `close`.

```rust
impl DatagramHandler<String> for UdpEcho {
    type Write = String;

    async fn read(&mut self, ctx: &mut DatagramContext<Self::Write>, msg: String) -> Result<()> {
        ctx.write_and_flush(format!("echo: {msg}")).await
    }
}
```

## Outbound

`Outbound<I>` converts the application type written by a handler into the next outbound type. The final outbound type must be encodable by the codec.

```rust
struct RenderResponse;

impl Outbound<Response> for RenderResponse {
    type Out = String;

    async fn write(
        &mut self,
        _ctx: &mut rs_netty::OutboundContext,
        msg: Response,
    ) -> rs_netty::Result<rs_netty::Flow<Self::Out>> {
        Ok(rs_netty::Flow::Next(msg.body))
    }
}
```

`OutboundContext` also exposes only identity information and does not allow direct writes.

## Macro Or Manual Impl

`#[handler]` is good for simple one-in/one-out final handlers and consume-only handlers. Write a manual impl when you need direct `Context` / `DatagramContext` access, explicit flush timing, multiple writes, connection close, or `channel()`.