# Architecture
The main path has four layers: transport, pipeline runtime, stage traits, and channel/context.
## Crate Layout
- `src/lib.rs`: public modules and common re-exports.
- `src/traits.rs`: `Inbound`, `Business`, `Handler`, `DatagramHandler`, `Outbound`, and `Flow`.
- `src/pipeline/stream`: TCP typed builder and runtime pipeline.
- `src/pipeline/datagram`: UDP typed builder and runtime pipeline.
- `src/pipeline/core`: shared `Identity`, `Then`, stage pipe traits, and builder state markers.
- `src/codec`: stream/datagram codec traits and built-in codecs.
- `src/context`: stage contexts, handler contexts, stats, and identity types.
- `src/channel`: external write handles and internal command enums.
- `src/tls.rs`: optional TLS context builders and server/client contexts behind the `tls` feature.
- `src/transport/tcp`: TCP server, client, connection runtime, and config.
- `src/transport/udp`: UDP server, client, socket runtime, and config.
- `src/life.rs`: lifecycle hook trait and close reasons.
- `rs-netty-macros`: the `#[handler]` attribute macro.
## TCP Runtime Flow
A TCP server calls the pipeline factory once for each accepted connection. A client can use either a reusable factory or `pipeline_instance`, which consumes one single-use pipeline.
The runtime flow is roughly:
```text
TcpListener / TcpStream
-> optional TLS accept/connect
-> read_buf
-> Decoder::decode
-> InboundPipe
-> BusinessPipe
-> Handler::read(Context<W>, msg)
-> Context outbox or Channel command queue
-> OutboundPipe
-> Encoder::encode
-> write_buf
-> flush/write_all
```
`StreamConnectionRuntime` selects over socket reads, external channel commands, and shutdown signals. Without an idle timeout it uses a no-timeout loop. With `idle_timeout`, it adds a read-idle timer. The timer is reset only by socket reads; outbound writes do not reset it.
## UDP Runtime Flow
UDP servers and clients run around one socket task. The pipeline is socket-level:
```text
UdpSocket::recv_from
-> DatagramDecoder::decode_datagram
-> InboundPipe
-> BusinessPipe
-> DatagramHandler::read(DatagramContext<W>, msg)
-> DatagramContext outbox or DatagramChannel command queue
-> OutboundPipe
-> DatagramEncoder::encode_datagram
-> pending_datagrams
-> flush/send_to
```
A UDP server does not currently create per-peer child pipelines. If you need per-peer state, store it in the handler explicitly, for example with `HashMap<SocketAddr, State>`.
## Static Stage Composition
The builder composes stages at the type level as `Then<A, B>`. `Identity` means that a direction has no user stages. Runtime `InboundPipe`, `BusinessPipe`, and `OutboundPipe` process `Then` recursively:
- `Flow::Next(value)` forwards the value to the next stage.
- `Flow::Stop` stops processing the current message direction without treating it as an error.
- `Err` is mapped by the connection/socket runtime into decode, encode, handler, or runtime errors.
The main path does not use dynamic `Box<dyn Handler>` pipeline dispatch. Pipeline types are built from generic static stage composition.
## Channel And Context
`Context<W>` and `DatagramContext<W>` are the write entry points inside final handlers. They hold a handler-local outbox, which is useful for multiple writes and explicit flush boundaries during one read.
`Channel<W>` and `DatagramChannel<W>` are cloneable external handles. They send commands to the connection/socket task through a bounded Tokio `mpsc` queue. TCP channels expose `stats()`, `capacity()`, `max_capacity()`, and `is_closed()`; UDP channels expose socket identity and queue state.