nexus-web
Low-latency WebSocket, HTTP/1.1, and REST primitives. Sans-IO, zero-copy, SIMD-accelerated. Framework-agnostic — works with mio, io_uring, tokio, or raw syscalls.
Extracted from nexus-net 0.7.x. Protocol state machines operate on byte slices — no async runtime, no I/O layer.
Performance
vs tungstenite (in-memory parse, pinned to cores 0,2)
| Payload | Type | nexus-web | tungstenite | Speedup |
|---|---|---|---|---|
| 40B | binary parse | 19ns (52M/s) | 61ns (16M/s) | 3.2x |
| 128B | binary parse | 24ns (42M/s) | 75ns (13M/s) | 3.1x |
| 512B | binary parse | 49ns (20M/s) | 105ns (10M/s) | 2.1x |
| 77B | JSON quote parse+deser | 146ns (6.9M/s) | 205ns (4.9M/s) | 1.4x |
| 40B | binary TCP loopback | 30ns (33M/s) | 66ns (15M/s) | 2.2x |
rdtsc cycle distribution (pinned to core 0, batch=64)
| Path | p50 | p90 | p99 | p99.9 |
|---|---|---|---|---|
| text unmasked 128B | 39 | 39 | 43 | 65 |
| binary unmasked 128B | 35 | 36 | 44 | 129 |
| text masked 128B | 52 | 53 | 58 | 124 |
| apply_mask 128B | 12 | 12 | 16 | 31 |
| encode_text 128B server | 10 | 11 | 22 | 39 |
| throughput 100x128B /msg | 28 | 28 | 44 | 91 |
At 3GHz: 39 cycles = 13ns. In-memory throughput: 107M msg/sec (28 cycles/msg).
vs reqwest (REST HTTP/1.1 client)
| Benchmark | nexus-web | reqwest | Speedup |
|---|---|---|---|
| POST build+write+parse (mock) p50 | 494 cycles (165ns) | 1,549 cycles (516ns) build-only | 3.1x |
| TCP loopback round-trip p50 | 22,924 cycles (7.6us) | 62,802 cycles (20.9us) | 2.7x |
| TCP loopback throughput | 114K req/sec | 39K req/sec | 2.9x |
517/517 Autobahn WebSocket conformance. 16/16 httpbin.org REST conformance.
Architecture
Application
|
+-- WebSocket REST HTTP/1.1
| ^ Message<'a> ^ Request<'a> / RestResponse<'a>
| FrameReader / FrameWriter RequestWriter / ResponseReader (sans-IO)
| ^ plaintext bytes ^ plaintext bytes
| +----------+----------------+
| TlsCodec (optional, nexus-net)
| ^ encrypted bytes
+--------------+
I/O (your choice)
Each layer is a pure state machine. No syscalls, no sockets, no async. Bytes in, messages out.
Async Adapters
For async usage, see nexus-async-web — thin async wrappers over the same sans-IO primitives. Supports both tokio and nexus-async-rt backends.
Quick Start
[]
# WebSocket + HTTP, no TLS
= "0.8"
# With TLS (rustls + aws-lc-rs via nexus-net)
= { = "0.8", = ["tls"] }
# Everything (TLS + socket options + bytes)
= { = "0.8", = ["full"] }
WebSocket Client (ws://)
use ;
let mut ws = builder.connect?;
ws.send_text?;
loop
WebSocket Client (wss://)
use Client;
use TlsConfig; // re-exported from nexus-net
let tls = new?;
let mut ws = builder.tls.connect?;
REST Client (HTTP/1.1, blocking)
use ;
use ResponseReader;
let mut writer = new?;
writer.default_header?;
let mut reader = new.max_body_size;
let tls = new?;
let mut conn = builder.tls.connect?;
let req = writer.get
.query
.query
.finish?;
let resp = conn.send?;
println!;
Sans-IO (decoupled from sockets)
use ;
let = pair;
reader.read_from?;
for _ in 0..8
Modules
ws — WebSocket (RFC 6455)
FrameReader— sans-IO inbound parser. Frame parsing, fragment assembly, control frame interleaving, SIMD masking, UTF-8 validation.FrameWriter— sans-IO outbound encoder.Client<S>— convenience I/O wrapper with HTTP upgrade handshake.Message<'a>—Text(&str),Binary(&[u8]),Ping,Pong,Close.
http — HTTP/1.1 Primitives
RequestReader/ResponseReader— sans-IO HTTP parsers backed by httparse (SIMD-accelerated).ChunkedDecoder— sans-IO chunked transfer encoding decoder.write_request/write_response— zero-alloc HTTP construction.
rest — HTTP/1.1 REST Client
RequestWriter— sans-IO request encoder with typestate builder.Client<S>— pure transport. TLS handled at the stream level.RestResponse<'a>— borrows fromResponseReader.
Features
| Feature | Default | Description |
|---|---|---|
tls |
No | TLS support via nexus-net (rustls + aws-lc-rs) |
socket-opts |
No | Socket options via socket2 |
bytes |
No | bytes::Bytes conversion on OwnedMessage and RestResponse |
full |
No | tls + socket-opts + bytes |
Design Decisions
Zero-copy inbound. Message::Text(&str) borrows from the reader's
internal buffer. No heap allocation per message.
Sans-IO. Protocol logic is a pure state machine. The same
FrameReader works with blocking sockets, mio, io_uring, tokio, or
kernel bypass.
SIMD-accelerated. XOR masking uses SSE2/AVX2. UTF-8 validation uses simdutf8. HTTP header parsing uses httparse (SIMD vectorized).
No permessage-deflate. Exchanges that compress use application-level gzip, not WebSocket compression.
Testing
# Autobahn conformance (requires Podman)
# httpbin.org conformance (requires network)
# Benchmarks