Why Is It Designed This Way?
Why separate quinn-proto from sockets?
The protocol is a function of datagrams, time, configuration, and prior state. Keeping it I/O-free enables deterministic simulated-time tests, fuzzing, custom event loops, and reasoning about loss without real sleeps or packet timing.
Why one endpoint driver and many connection drivers?
One UDP socket carries packets for many QUIC connections. The endpoint owns routing and stateless responses; each connection owns encryption, streams, acknowledgement, loss, congestion, and timers. Separate drivers reflect that ownership while channels carry protocol events between them.
Why individual stream wakers?
A packet may make one stream readable without helping hundreds of others.
Maps keyed by StreamId wake only the blocked reader or writer affected by a
protocol event, preventing a thundering herd.
Why abstract the runtime?
QUIC needs spawn, clock, timer, UDP receive, and UDP send—not Tokio specifically. Small traits let Tokio and smol supply those capabilities and let tests control time.
Why explicit loop budgets?
A busy UDP socket or connection can remain continuously ready. Datagram-count and time bounds force driver polls to yield so unrelated tasks retain latency.
Why does dropping a handle not instantly forget protocol state?
QUIC must send close/reset frames, release connection IDs, and drain peer-visible
state. Drop triggers protocol actions; endpoint wait_idle observes when all
connections have actually drained.