Feature-gated binary wire protocol (feature = wire)#80
Closed
joaquinbejar wants to merge 4 commits intomainfrom
Closed
Feature-gated binary wire protocol (feature = wire)#80joaquinbejar wants to merge 4 commits intomainfrom
joaquinbejar wants to merge 4 commits intomainfrom
Conversation
Add a feature-gated `wire` flag with optional `zerocopy = "0.8"` dependency. Introduce the binary frame codec (`[len:u32 LE | kind:u8 | payload]`), the `WireError` taxonomy (manual `Display`, no `thiserror`), and the stable `MessageKind` discriminants (`#[repr(u8)] #[non_exhaustive]`). Inbound codes occupy `0x01..=0x7F`, outbound `0x80..=0xFF`. This commit ships the wire scaffolding only — the per-message inbound/outbound modules land in the next commit.
Inbound (`src/wire/inbound/`) — `NewOrderWire` (48 B),
`CancelOrderWire` (24 B), `CancelReplaceWire` (40 B), and
`MassCancelWire` (24 B). Each is `#[repr(C, packed)]` with
`zerocopy::{FromBytes, IntoBytes, Unaligned, Immutable,
KnownLayout}` derives, a `const _: () = assert!(size_of::<…>()
== N)` size guard, an `as_payload_bytes()` accessor (so callers
do not need to import `zerocopy`), and a `decode_*` helper that
returns `WireError::InvalidPayload` on size mismatch. Decoding is
safe — `#![deny(unsafe_code)]` stays on.
Outbound (`src/wire/outbound/`) — `ExecReport` (44 B),
`TradePrintWire` (48 B), `BookUpdateWire` (32 B). Outbound uses
explicit byte-cursor encoders (`Vec<u8>::extend_from_slice`).
`status_to_wire` maps `OrderStatus` to its `STATUS_*` discriminant.
Wire ↔ domain mapping at the boundary —
`impl TryFrom<&NewOrderWire> for OrderType<()>` copies each
packed field into a stack local first (taking a reference to a
packed field is UB), validates the side / TIF / order_type
discriminants, and rejects negative prices.
`MassCancel` rejects unknown `scope` bytes at decode time.
Round-trip `proptest` tests in every new module — encode through
the framer, decode back, assert byte-for-byte equality.
`examples/src/bin/wire_roundtrip.rs` builds a `NewOrderWire`, encodes it via the framer, decodes the frame, validates the `MessageKind` byte, decodes the payload, mirrors the packed fields onto stack locals (taking a reference to a packed field is UB), and converts the result into a domain `OrderType<()>`. Every step is logged via `tracing::info!`. The example is gated by `required-features = ["wire"]` in `examples/Cargo.toml`, mirroring the existing `special_orders` pattern.
Add `doc/wire-protocol.md` with per-message offset / size / field / type / notes layout tables for every inbound and outbound message, the `MessageKind` discriminant table, the framing rule (`[len:u32 LE | kind:u8 | payload]` where `len` covers `kind + payload`), and the LE-endianness statement. Append a new sub-block to the existing 0.7.0 section in `CHANGELOG.md` covering the feature flag, framing rule, endianness, discriminant table, fixed-size packed inbound layouts via `zerocopy`, byte-cursor outbound encoders, round-trip proptests, and the `wire_roundtrip` example. Note that `JSON` and `bincode` paths are unchanged — the wire protocol is additive. `README.md` is regenerated via `cargo readme` to mirror the new What's New entry that already shipped with the lib.rs scaffolding commit. The unrelated `tests/unit/replay_determinism.rs` import-grouping fix is a `cargo fmt --all` follow-up.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
wire(default off) gates a length-prefixed binaryframing — every frame is
[len:u32 LE | kind:u8 | payload], wherelencoverskind + payload(the 4-bytelenprefix itself isexcluded). All multi-byte integers are little-endian. Existing JSON
and bincode paths are unchanged — the wire protocol is purely
additive.
MessageKindenum (#[repr(u8)] #[non_exhaustive]) withinbound discriminants
0x01NewOrder,0x02CancelOrder,0x03CancelReplace,0x04MassCanceland outbound0x81ExecReport,0x82TradePrint,0x83BookUpdate.#[repr(C, packed)]+ thezerocopy 0.8traitcohort (
FromBytes,IntoBytes,Unaligned,Immutable,KnownLayout); each has a compile-timeconst _: () = assert!(size_of::<…>() == N)size guard. Decoding issafe —
#![deny(unsafe_code)]stays on.(
Vec<u8>::extend_from_slice);status_to_wiremapsOrderStatus→
STATUS_*.impl TryFrom<&NewOrderWire> for OrderType<()>doesthe wire ↔ domain conversion at the boundary, copying packed
fields into stack locals first (taking a reference to a packed
field is UB).
Display,#[non_exhaustive]WireErrormatching the crate's existing manual style — no
thiserror.proptesttests in everysrc/wire/{inbound,outbound}/*.rsmodule — encode through theframer, decode back, assert byte-for-byte equality.
doc/wire-protocol.mdships per-message offset / size / field /type / notes layout tables, the
MessageKinddiscriminant table,the framing rule, and the LE-endianness statement.
examples/src/bin/wire_roundtrip.rs(gated byrequired-features = ["wire"]).Test plan
cargo fmt --allcargo clippy --all-targets --features wire -- -D warningscargo clippy --all-targets -- -D warningscargo test --features wire(567 + 25 + 386 + 41 passed)cargo test(535 + 25 + 386 + 41 passed — the wire suite dropsto the lib's normal test count when the feature is disabled, the
rest is unchanged)
cargo build --release --features wirecargo run --bin wire_roundtrip --manifest-path examples/Cargo.toml --features wiremake readme— README regenerated and committed