rs-netty 1.1.0

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

这一章给出新增 codec、handler 和 example 的最小路径。

## Add A TCP Codec

实现 `Decoder` 和 `Encoder<T>`。如果 decode 输出和 encode 输入不同,也可以实现 `Decoder` 在一个类型上、`Encoder<T>` 在同一个类型上,并通过 outbound stage 把应用响应转成 `T`。

```rust
use bytes::{Buf, BufMut, Bytes, BytesMut};
use rs_netty::{codec::{Decoder, Encoder}, Error, Result};

struct LengthCodec;

impl Decoder for LengthCodec {
    type Item = Bytes;

    fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>> {
        if src.len() < 4 {
            return Ok(None);
        }

        let len = u32::from_be_bytes([src[0], src[1], src[2], src[3]]) as usize;
        if src.len() < 4 + len {
            return Ok(None);
        }

        src.advance(4);
        Ok(Some(src.split_to(len).freeze()))
    }
}

impl Encoder<Bytes> for LengthCodec {
    fn encode(&mut self, item: Bytes, dst: &mut BytesMut) -> Result<()> {
        let len = u32::try_from(item.len()).map_err(|err| Error::Encode(err.to_string()))?;
        dst.put_u32(len);
        dst.extend_from_slice(&item);
        Ok(())
    }
}
```

仓库 benchmark 中的 `LengthCodec` 使用更复用的方式:内部组合 `LengthFieldBasedFrameDecoder` 和 `LengthFieldPrepender`。

## Add A UDP Codec

实现 `DatagramDecoder` 和 `DatagramEncoder<T>`。每次 decode 输入就是一个 datagram payload:

```rust
use bytes::{Bytes, BytesMut};
use rs_netty::{codec::{DatagramDecoder, DatagramEncoder}, Result};

struct RawDatagram;

impl DatagramDecoder for RawDatagram {
    type Item = Bytes;

    fn decode_datagram(&mut self, src: &[u8]) -> Result<Self::Item> {
        Ok(Bytes::copy_from_slice(src))
    }
}

impl DatagramEncoder<Bytes> for RawDatagram {
    fn encode_datagram(&mut self, item: Bytes, dst: &mut BytesMut) -> Result<()> {
        dst.extend_from_slice(&item);
        Ok(())
    }
}
```

这和内置 `BytesDatagramCodec` 非常接近。

## Add An Inbound Handler

实现 `Inbound<I>`,返回 `Flow<Out>`:

```rust
struct ParseRequest;

impl rs_netty::Inbound<String> for ParseRequest {
    type Out = Request;

    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(Request { body: msg }))
    }
}
```

如果想过滤消息而不是继续传递,返回 `Flow::Stop`。

## Add An Outbound Handler

实现 `Outbound<I>`,把应用响应类型转换为下游类型:

```rust
struct RenderResponse;

impl rs_netty::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))
    }
}
```

在 pipeline 中放到 final handler 后面:

```rust
pipeline()
    .codec(LineCodec::new())
    .inbound(ParseRequest)
    .handler(Router)
    .outbound(RenderResponse);
```

## Add A Complete Example

建议步骤:

1. `examples/` 下新增一个小而完整的 `.rs` 文件。
2. 在根 `Cargo.toml` 增加 `[[example]]` 条目,按需设置 `required-features`3. example 中优先使用现有 codec 和公开 traits,避免依赖 `pub(crate)` runtime。
4. 如果是 TCP,使用 `pipeline()`;如果是 UDP,使用 `datagram_pipeline()`5. 如果 handler 简单,使用 `#[handler]`;如果要手动 flush、多次写或关闭连接,手写 impl。
6. 加一个 trybuild pass 用例,确保 public API 编译形状不回退。
7. 运行 `cargo test` 和相关 feature test。

完整 TCP typed chain 可以参考 `examples/tcp_typed_chain.rs`;完整 UDP typed chain 可以参考 `examples/udp_typed_chain.rs`。