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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
//! Thubo: a high-performance TX/RX network pipeline featuring strict priority
//! scheduling, automatic batching, and fragmentation.
//!
//! Thubo is designed for applications that demand strict, priority-based
//! message delivery with configurable congestion control. By managing
//! independent priority queues and fragmenting messages within each queue,
//! Thubo enables high-priority traffic to seamlessly interleave and preempt
//! lower-priority flows, ensuring responsive behavior even under heavy load.
//!
//! The priority-based interleaving is particularly valuable for protocols that
//! experience head-of-line blocking (such as TCP/TLS), where a single large
//! low-priority message could otherwise delay urgent high-priority traffic.
//!
//! # Overview
//!
//! The diagram below illustrates the TX/RX network pipeline in operation, using
//! all 4 priority queues (High, Medium, Low, Background).
//!
//! ```text
//! .....
//! APPLICATION SEND User code :
//! ┌─────────────┐ ┌────┐ ┌────────┐ ┌────┐ ┌────┐ :
//! │ B1 │ │ L1 │ │ M1 │ │ H1 │ │ H2 │ :
//! └──┬──────────┘ └─┬──┘ └──┬─────┘ └─┬──┘ └─┬──┘ :
//! t0 t1 t2 t3 t4 :
//! ▼ ▼ ▼ ▼ ▼ :
//! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :
//! TX PIPELINE Thubo code :
//! ┌──────────────────────────────────────────────────────────────┐ :
//! │ Queues: │ :
//! │ P0 (High): [H1][H2] ← t3 ← t4 │ :
//! │ P1 (Medium): [M1a, M1b] ← t2 │ :
//! │ P2 (Low): [L1a, L1b] ← t1 │ :
//! │ P3 (Background): [B1a, B1b, B1c] ← t0 │ :
//! | | :
//! │ t0 t1 t2 t3 t4 │ :
//! │ Pull Order: B1a → B1b → L1a → M1a → H1 H2 → M1b → L1b → B1c │ :
//! │ │ :
//! │ TX Stream: [B1a][B1b][L1a][M1a][H1 H2][M1b][L1b][B1c] │ :
//! └───────────┬──────────────────────────────────────────────────┘ :
//! | .....
//! ▼ Network
//! .....
//! RX PIPELINE Thubo code :
//! ┌──────────────────────────────────────────────────────────────┐ :
//! │ RX Stream: [B1a][B1b][L1a][M1a][H1 H2][M1b][L1b][B1c] │ :
//! │ │ :
//! │ Reassembled Messages: B1, L1, M1, H1, H2 │ :
//! │ │ :
//! │ Delivered by Priority: H1 → H2 → M1 → L1 → B1 │ :
//! └───────────┬──────────────────────────────────────────────────┘ :
//! ▼ :
//! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :
//! APPLICATION RECEIVE User code :
//! ┌────┐ ┌────┐ ┌────────┐ ┌────┐ ┌─────────────┐ :
//! │ H1 │ │ H2 │ │ M1 │ │ L1 │ │ B1 │ :
//! └────┘ └────┘ └────────┘ └────┘ └─────────────┘ :
//! .....
//! ```
//!
//! At the *Application Send* stage, five messages (*B1*, *L1*, *M1*, *H1*, and *H2*) are pushed into the system at
//! different times (*t0*, *t1*, *t2*, *t3*, and *t4* respectively). These messages enter the *TX Pipeline*, where they
//! may be fragmented if too large and assigned to queues based on their priority.
//!
//! The highest priority queue, *P0 (High)*, contains the non-fragmented messages *H1* and *H2*, while the medium
//! priority queue, *P1 (Medium)*, holds the fragments *M1a* and *M1b*. The low priority queue, *P2 (Low)*, contains
//! the fragments *L1a* and *L1b*. The lowest priority queue, *P3 (Background)*, contains the fragments *B1a*, *B1b*,
//! and *B1c*.
//!
//! The *TX Pipeline* schedules and pulls fragments in a specific order: *B1a*,
//! *B1b*, *L1a*, *M1a*, then batches *H1* and *H2* together, followed by *M1b*,
//! *L1b*, and *B1c*. When high-priority messages *H1* and *H2* arrive, they
//! preempt the transmission of lower-priority fragments, according to the strict
//! priority scheduling. The batched high-priority messages *[H1 H2]* are
//! transmitted together as a single unit over the *Network* to the *RX
//! Pipeline*.
//!
//! Upon arrival, the *RX Pipeline* receives the fragments in the same order
//! they were sent: *B1a*, *B1b*, *L1a*, *M1a*, *[H1 H2]*, *M1b*, *L1b*, and
//! *B1c*. The fragments are reassembled into their original messages: *B1*,
//! *L1*, *M1*, *H1*, and *H2*.
//!
//! However, the delivery to the *Application Receive* follows the priority
//! order, with *H1* delivered first, followed by *H2*, then *M1*, *L1*, and
//! finally *B1*. This process ensures that higher-priority messages are
//! delivered before lower-priority ones, even if they arrive later in the
//! stream.
//!
//! # Features
//!
//! - **4-level Priority System**: message ordering with strict priority scheduling (see [`Priority`])
//! - **Congestion Control**: choose between blocking ([Block](`CongestionControl::Block`)) or dropping messages
//! ([Drop](`CongestionControl::Drop`)) under load
//! - **Express Delivery**: send urgent messages immediately without batching for lowest latency
//! - **Automatic Batching**: small messages are transparently aggregated for highest throughput
//! - **Automatic Fragmentation**: large messages are transparently fragmented and reassembled, allowing higher priority
//! messages to interleave and preempt ongoing transmissions
//! - **Zero-Copy Buffers**: efficient buffer management with [`Chunk`] and [`Bytes`] types
//!
//! # Quick Start
//!
//! ```no_run
//! use thubo::*;
//! use tokio::net::TcpStream;
//!
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//! // Create a TCP connection
//! let stream = TcpStream::connect("127.0.0.1:8080").await?;
//! let (reader, writer) = stream.into_split();
//!
//! // Create bidirectional channel with buffer capacity and batch size
//! let (mut sender, sender_task) = thubo::sender(writer).build();
//! let (mut receiver, receiver_task) = thubo::receiver(reader).build();
//!
//! // Set the QoS to send messages with high-priority
//! sender.qos(
//! QoS::default()
//! .with_priority(Priority::High)
//! .with_congestion_control(CongestionControl::Block),
//! );
//! sender.send(&Bytes::from("urgent message")).await?;
//!
//! // Receive messages in priority order
//! let (msg, qos): (Bytes, QoS) = receiver.recv().await?;
//! println!("Received message with priority: {:?}", qos.priority());
//!
//! Ok(())
//! }
//! ```
//!
//! # Buffer management
//!
//! Thubo provides efficient buffer management through two key types: [`Chunk`] and [`Bytes`].
//!
//! ## Chunk
//!
//! [`Chunk`] is a reference-counted, immutable buffer that supports cheap cloning and view creation:
//!
//! ```
//! use thubo::Chunk;
//!
//! // Create a chunk from data
//! let data = vec![1, 2, 3, 4, 5];
//! let chunk: Chunk = data.into();
//!
//! // Cheap clone - shares the underlying buffer
//! let chunk2 = chunk.clone();
//!
//! // Create a view into a portion of the buffer (zero-copy)
//! let view = chunk.view(1..4).unwrap();
//! assert_eq!(view.as_slice(), &[2, 3, 4]);
//! ```
//!
//! ## Bytes
//!
//! [`Bytes`] is a collection of one or more [`Chunk`]s that can represent non-contiguous memory:
//!
//! ```
//! use thubo::Bytes;
//!
//! let mut bytes = Bytes::new();
//! bytes.push("Hello ".as_bytes().to_vec().into());
//! bytes.push("World!".as_bytes().to_vec().into());
//!
//! // Bytes provides Read, Seek, and Write interface
//! use std::io::Read;
//! let mut buf = vec![0u8; 12];
//! let mut reader = bytes.reader();
//! reader.read_exact(&mut buf).unwrap();
//! ```
//!
//! ## Batching
//!
//! When **batching** multiple small messages, Thubo copies data into a single contiguous memory
//! region before writing to the network. This optimization reduces system call overhead:
//!
//! ```text
//! Message 1: [A A A]
//! Message 2: [B B] Copy into Batch Buffer:
//! Message 3: [C C C C] → single buffer → [A A A|B B|C C C C]
//! ↓
//! Single write() syscall
//! ```
//!
//! This copy is necessary to achieve maximum throughput by minimizing the number of network writes.
//!
//! ## Fragmentation
//!
//! When **fragmenting** large messages, Thubo uses zero-copy [`Bytes`] views. No data is copied;
//! instead, partial views of the buffer are created and sent separately:
//!
//! ```text
//! Original Buffer: [▥▥▥▥▥▥▥▥▥▥▥▥▥▥▥▥▥▥▥▥▥▥▥▥]
//! ↓ Create views (zero-copy)
//! Fragment 1: [▥▥▥▥▥▥▥▥]
//! Fragment 2: [▥▥▥▥▥▥▥▥]
//! Fragment 3: [▥▥▥▥▥▥▥▥]
//! ↓
//! Each fragment sent as separate write()
//! ```
//!
//! This enables high-priority messages to interleave between fragments without copying data.
//!
//! ## Buffer reuse
//!
//! The [`Boomerang`](`crate::collections::Boomerang`) type allows you to get back the underlying buffer once it's no
//! longer needed, enabling buffer reuse and reducing allocations.
//!
//! When [`send()`](`Sender::send`) returns, your message has been queued in the TX pipeline but **it may not yet be
//! written to the network**. A background task asynchronously handles batching, fragmentation, and network
//! transmission. The [`Boomerang`](`crate::collections::Boomerang`) future completes only after the data has been fully
//! transmitted, at which point you can safely reclaim and reuse the buffer.
//!
//! ```no_run
//! use thubo::{Bytes, collections::Boomerang};
//! use tokio::net::TcpStream;
//!
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//! // Create a TCP connection
//! let stream = TcpStream::connect("127.0.0.1:8080").await?;
//! let (reader, writer) = stream.into_split();
//!
//! // Create bidirectional channel with buffer capacity and batch size
//! let (mut sender, sender_task) = thubo::sender(writer).build();
//! let (mut receiver, receiver_task) = thubo::receiver(reader).build();
//!
//! let mut buffer = vec![42u8; 42];
//! loop {
//! let (bytes, boomerang) = Boomerang::new(buffer);
//! sender.send(Bytes::from(bytes)).await?; // Pass the ownership to not keep any reference
//! // Wait for the buffer to return and ready to be reused
//! buffer = boomerang.await.unwrap();
//! }
//!
//! Ok(())
//! }
//! ```
//!
//! # Performance Considerations
//!
//! ## Batching
//!
//! Messages are batched to improve throughput by amortizing system call overhead
//! and header costs. Thubo provides two knobs to control batching behavior:
//!
//! ### Batch Size
//!
//! Configure via [`SenderBuilder::batch_size()`]. Controls the maximum size of
//! each batch. **Most applications should use the default and rarely need to
//! modify this setting.**
//!
//! You may want to adjust batch size only when:
//! - **Matching MTU**: Set batch size to match your network's Maximum Transmission Unit to avoid IP fragmentation
//! - **Controlling head-of-line blocking**: Smaller batches allow higher priority messages to preempt lower priority
//! traffic more frequently, reducing the maximum latency for urgent messages
//!
//! Trade-offs:
//! - **Smaller batches** (1-4KB): Lower latency, more frequent preemption opportunities, more system call overhead
//! - **Larger batches** (8-64KB): Higher throughput, less preemption flexibility, slightly higher latency
//! - **Maximum**: 64KB (protocol limit - batch size is represented on the wire as an unsigned 16-bit integer)
//!
//! **Note**: Moving to 32-bit batch sizes would be inadvisable in any case. Larger batches would:
//! - Significantly worsen head-of-line blocking, as lower priority messages would block high priority traffic for
//! longer periods
//! - Increase network transmission delay, causing unacceptable latency for interactive applications
//! - Reduce the effectiveness of priority-based preemption, which is a core design goal of Thubo
//!
//! ### Batch Timeout
//!
//! Configure via [`SenderBuilder::timeout_batch()`]. Controls how long a batch
//! can remain uncommitted before being forcibly flushed:
//! - **Lower values** (1-10μs): Reduces latency for sparse traffic, more frequent small batches
//! - **Higher values** (100μs-1ms): Better throughput for burst traffic, may increase latency
//! - **Default**: 10μs
//!
//! The pipeline automatically flushes batches when they stop growing, preventing
//! idle batches from waiting unnecessarily.
//!
//! ### Express Mode
//!
//! Set via [`QoS::express()`]. Bypasses batching entirely for critical messages
//! that require minimum latency, sending them immediately regardless of batch
//! state.
//!
//! ## Priority Starvation
//!
//! Thubo uses **strict priority** scheduling: higher priority messages are
//! always processed first. Sustained high-priority traffic can starve lower
//! priorities. Design your priority usage accordingly:
//! - Use [`Priority::High`] sparingly for truly critical messages
//! - Most traffic should use [`Priority::Medium`] (default)
//! - Use [`Priority::Low`] for non time-sensitive data
//! - Reserve [`Priority::Background`] for non-critical bulk transfers
//!
//! # Acknowledgements
//!
//! The design of Thubo is inspired by the transmission pipeline architecture of
//! [Eclipse Zenoh](https://zenoh.io). The author of Thubo is the original author
//! of the transmission pipeline in Zenoh.
pub use *;
pub use ;
pub use ;
pub use ;