# Design Goals
rs-netty is not a direct port of Java Netty. Its goal is to take the useful pipeline/handler/channel model and express it in a Rust-native way.
## Keep The Useful Shape
The framework keeps these concepts:
- codecs sit at pipeline boundaries and convert between bytes/datagrams and typed messages.
- inbound stages process decoded inbound messages.
- final handlers implement application semantics and write application-level responses.
- outbound stages convert handler writes into values the codec can encode.
- channel handles can write, flush, or close from outside the current handler.
- lifecycle hooks can observe server, connection, and UDP socket startup/shutdown.
## Use Rust Types Instead Of Dynamic Pipeline Mutation
Java Netty's dynamic pipeline is flexible, but many mistakes show up at runtime: handlers are in the wrong order, upstream message types do not match downstream handlers, or a TCP pipeline is used with UDP. rs-netty encodes these constraints in builder types:
```text
codec -> inbound* -> business* -> handler -> outbound*
```
Only methods that are valid in the current state exist. For example, `.handler(...)` is unavailable before `.codec(...)`; `.inbound(...)` is unavailable after `.handler(...)`; and the final outbound type must be encodable by the selected codec.
The repository's trybuild tests cover these failure modes, including:
- `fail_stream_handler_before_codec.rs`
- `fail_stream_outbound_before_handler.rs`
- `fail_stream_type_mismatch_inbound_to_handler.rs`
- `fail_stream_final_encoder_mismatch.rs`
- `fail_udp_with_stream_pipeline.rs`
- `fail_tcp_with_datagram_pipeline.rs`
## Separate TCP And UDP Builders
TCP uses `pipeline()` and requires codecs to implement `Decoder` and `Encoder<T>`. UDP uses `datagram_pipeline()` and requires codecs to implement `DatagramDecoder` and `DatagramEncoder<T>`.
This is a type boundary, not just a naming convention. `TcpServer::pipeline` accepts only `IntoStreamPipeline`; `UdpServer::pipeline` accepts only `IntoDatagramPipeline`. Mixing TCP and UDP pipeline builders fails at compile time.
## Prefer Owned Messages
The public API does not expose Java Netty-style reference-counted `ByteBuf`. Codecs and handlers use owned types such as `String`, `bytes::Bytes`, and user-defined structs. This fits Rust ownership and avoids ref-count lifetime mistakes.
## Bounded Queues And Explicit Flush
`Channel` and `DatagramChannel` use bounded Tokio `mpsc` queues internally. `outbound_queue_size` controls the external command queue size. When the queue is full, write calls wait for capacity instead of growing without bound.
Write and flush are explicit:
- `write` only queues or stages data.
- `flush` pushes already staged data to the socket.
- `write_and_flush` writes and creates a flush boundary.
This lets throughput-oriented code batch writes while latency-oriented code can flush explicitly.
## Zero Unsafe
The crate root uses `#![deny(unsafe_code)]`, and `rs-netty-macros` does the same. The current library and macro crate do not use `unsafe` on the main implementation path.