1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
//! Tokio-native typed TCP/UDP pipeline framework inspired by Netty.
//!
//! `rs-netty` keeps the familiar channel, pipeline, and handler shape while
//! using Rust's type system to validate pipeline order and message transitions
//! at compile time.
//!
//! # Quick start
//!
//! ```no_run
//! use rs_netty::{codec::LineCodec, handler, pipeline, Result, TcpServer};
//!
//! #[tokio::main]
//! async fn main() -> Result<()> {
//! TcpServer::bind("127.0.0.1:9000")
//! .pipeline(|| {
//! pipeline()
//! .codec(LineCodec::new())
//! .handler(Echo)
//! })
//! .run()
//! .await
//! }
//!
//! struct Echo;
//!
//! #[handler(Echo)]
//! async fn echo(msg: String) -> Result<String> {
//! Ok(msg)
//! }
//! ```
//!
//! # Pipeline shape
//!
//! TCP pipelines are built with [`pipeline()`] and UDP pipelines are built with
//! [`datagram_pipeline()`]. The builder only exposes methods that are valid in
//! the current state, so invalid orderings such as adding a handler before a
//! codec fail to compile.
//!
//! A TCP pipeline has this shape:
//!
//! ```text
//! codec -> inbound* -> business* -> handler -> outbound*
//! ```
//!
//! A UDP pipeline has the same typed stage model, but processes whole datagrams
//! rather than a byte stream.
//!
//! # Write and flush semantics
//!
//! Writes issued through [`Context`] are staged in the current handler's
//! outbox and then encoded into the connection write buffer. `flush` and
//! `write_and_flush` request a local socket flush immediately; dropping their
//! returned handles is fire-and-forget, while awaiting them waits until the
//! local socket write completes. [`DatagramContext`] keeps the same manual
//! flush model for datagram sockets.
//!
//! Writes issued through [`Channel`], [`TcpClientHandle`], [`DatagramChannel`],
//! or [`UdpClientHandle`] are sent through the connection/socket command queue
//! and follow the same manual flush semantics. The queue is bounded by the
//! configured outbound queue size.
//!
//! # Handler ergonomics
//!
//! Simple handlers can use the [`handler`] attribute macro:
//!
//! ```no_run
//! # use rs_netty::{handler, Result};
//! struct Echo;
//!
//! #[handler(Echo)]
//! async fn echo(msg: String) -> Result<String> {
//! Ok(msg)
//! }
//! ```
//!
//! A handler function that returns `Result<Out>` automatically writes and
//! flushes `Out` back through the pipeline. A function that returns `Result<()>`
//! consumes the inbound message without automatically writing; in that case use
//! `#[handler(TypeName, write = WriteType)]` so the macro can set
//! `Handler::Write`.
//!
//! Write a manual [`Handler`] or [`DatagramHandler`] implementation when the
//! logic needs direct access to [`Context`] or [`DatagramContext`], such as
//! explicit flush timing or multiple writes for one inbound message.
//!
//! # Client pipeline choices
//!
//! [`TcpClient::pipeline`] accepts a reusable factory closure, matching the
//! server API and working well for stateless or cloneable client handlers.
//! [`TcpClient::pipeline_instance`] accepts one already-built pipeline and
//! consumes it when the client connects. Prefer `pipeline_instance` when a
//! client handler owns one-shot state, such as `tokio::sync::oneshot::Sender`.
pub use ;
pub use ;
pub use ;
pub use ;
pub use pipeline;
pub use datagram_pipeline;
pub use handler;
pub use ;
pub use ;
pub use TcpServer;
pub use ;
pub use UdpServer;