rs-netty 1.1.0

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

UDP uses datagram pipelines. The model is similar to TCP, but the boundary is a complete datagram rather than a byte stream.

## Server

`UdpServer::bind(addr)` creates a socket server builder. `.pipeline(|| ...)` sets the socket-level pipeline factory:

```rust
use rs_netty::{codec::Utf8DatagramCodec, datagram_pipeline, handler, Result, UdpServer};

struct UdpEcho;

#[handler(UdpEcho)]
async fn udp_echo(msg: String) -> Result<String> {
    Ok(format!("echo: {msg}"))
}

let server = UdpServer::bind("127.0.0.1:0")
    .pipeline(|| {
        datagram_pipeline()
            .codec(Utf8DatagramCodec)
            .handler(UdpEcho)
    })
    .start()
    .await?;

server.shutdown();
server.wait().await?;
# Ok::<(), rs_netty::Error>(())
```

`UdpServerHandle` exposes `local_addr()`, `shutdown()`, and `wait()`.

## Client

`UdpClient::connect(remote_addr)` binds to `"0.0.0.0:0"` by default. Use `.bind(local_addr)` to choose a local address. `UdpClientHandle<W>` provides these methods for the default remote peer:

- `write(msg)`
- `flush()`
- `write_and_flush(msg)`

It also supports explicit peers:

- `write_to(peer_addr, msg)`
- `write_to_and_flush(peer_addr, msg)`

## Socket-Level Pipeline

A UDP server currently creates one socket-level pipeline, not a child pipeline per peer. For every datagram, the runtime creates new `DatagramInfo`, `InboundContext`, `BusinessContext`, `DatagramContext`, and `OutboundContext` values. `peer_addr()` is the sender of the current datagram.

If the application needs per-peer state, store it in the handler yourself:

```rust
use std::{collections::HashMap, net::SocketAddr};

struct PeerState;

struct StatefulUdp {
    peers: HashMap<SocketAddr, PeerState>,
}
```

## Configuration

UDP uses `UdpSocketConfig`:

- `read_buffer_capacity`: default 64 KiB; normalized to at least `max_datagram_size`.
- `write_buffer_capacity`: default 8 KiB.
- `max_datagram_size`: default 64 KiB.
- `outbound_queue_size`: default 1024.

Builder methods include:

- `read_buffer_capacity(value)`
- `write_buffer_capacity(value)`
- `max_datagram_size(value)`
- `outbound_queue_size(value)`

UDP currently has no TCP-style `tcp_nodelay`, connection stats, or idle timeout.

## Datagram Write Semantics

`DatagramContext::write(msg)` writes to the current datagram peer. `write_to(peer, msg)` writes to an explicit peer. Both only stage data in the handler-local outbox. `flush` or `*_and_flush` sends pending datagrams through `send_to`.

A UDP flush acknowledgement only means the local `send_to` call completed. It does not mean the peer received the datagram, and UDP still provides no ordering, retransmission, or reliability guarantee.