framed-codec
A cancel-safe, zero-allocation length-prefixed codec for tokio byte streams.
A personal systems project: a self-contained building block for streaming binary telemetry — drone and robot links, sensor feeds, any binary wire protocol — over anything that is AsyncRead + AsyncWrite.
The problem
Two bugs recur in hand-rolled async framing code. A read() returns whatever bytes happened to arrive, frequently half a frame, so code that assumes “one read = one frame” silently corrupts the stream. And read_exact() into a stack buffer inside a tokio::select! is not cancel-safe: if another branch wins, the partially-read bytes are discarded and the stream is desynchronised permanently.
The approach
A length-prefixed tokio_util::codec decoder/encoder where all partial-read state lives inside the Framed buffer, never on the stack — so the read future is cancel-safe and a select! can drop it mid-frame and resume exactly where it left off. The decoder validates the declared length before indexing, so a hostile or corrupt length is a clean protocol error, never a panic or an OOM. Decoding a frame produces a Copy value with no per-frame heap allocation.
What the tests prove
- A frame fed one byte at a time decodes exactly once, on the final byte.
- 50 frames fed in 7-byte chunks all reconstruct in order.
- A ~4 GiB declared length is a clean
InvalidDataerror, not a panic. - A frame split across the wire, with a
select!that cancels the read mid-frame, still decodes intact — the headline guarantee. - A property test: any frame, split at any boundary, round-trips bit-exact.
Five tests pass, plus one intentionally-ignored doctest.
Running it
cargo run --bin demo runs end-to-end over an in-process tokio::io::duplex pipe — no sockets, no ports. It deliberately splits one frame across two writes with a stall between them to prove the receiver reconstructs it intact, then goes silent to show a liveness heartbeat tripping a safe-state transition. The demo exits 0.
Source
The full crate — Cargo.toml, src/, tests/, and an inline rendering of every source file — is browsable at /projects/framed-codec/.