rsx-messages
The RSX wire records (Fill/BBO/Order*/…): fixed-layout #[repr(C, align(64))] structs with one CastRecord impl each, on top of rsx-cast. No runtime, no I/O.← All CratesDescription
rsx-messages Architecture
A library of fixed-layout wire records and one CastRecord impl
per record. No runtime, no I/O, no threading — the records are
plain #[repr(C, align(64))] structs that the rsx-cast
transport moves as opaque bytes.
What a record is
Each record is a #[repr(C, align(64))] struct laid out so that:
- The first field is
seq: u64.CastRecord::seqreturns it andset_seqwrites it; the transport stamps the sequence number in place with no re-encode. - The size is a multiple of 64 bytes (64 or 128 here), reached
with explicit
_pad/_pad0/_pad1fields.align(64)keeps a record on its own cache line(s). - Size and alignment are pinned by a compile-time assertion:
rust
const _: () = assert!(mem::size_of::<FillRecord>() == 128);
const _: () = assert!(mem::align_of::<FillRecord>() == 64);
A field edit that changes the layout breaks the build.
Price and Qty (from rsx-types) are #[repr(transparent)]
over i64, so embedding them costs nothing and keeps the record
byte-for-byte wire-stable.
The CastRecord contract
rsx-cast defines CastRecord with three methods:
fn seq(&self) -> u64;
fn set_seq(&mut self, seq: u64);
fn record_type() -> u16;
record_type() returns the crate's RECORD_* constant, which
the transport writes into the 16-byte header's record_type
field. A receiver dispatches on that field and reads the payload
in place. The transport knows nothing about the struct beyond
these three methods.
Type-space layout
Record-type discriminants (RECORD_*: u16) are the domain
layer's namespace; rsx_cast::protocol owns the transport-level
constants separately. Discriminants are contiguous except where
reserved for records other tiles own: RECORD_ORDER_REQUEST (9)
and RECORD_ORDER_RESPONSE (10) are held here so the numeric
space stays coordinated across the gateway and risk crates, even
though those structs are defined elsewhere.
Encode / decode
encode_<record>wrapsrsx_cast::encode_record(record_type, as_bytes(record))— it prepends the 16-byte header and returns an ownedVec<u8>. Allocating; used off the hot path (tests, tools). The hot path uses the transport's zero-copy framing (WalWriter::prepare/CastSender::send_framed) directly.decode_<record>is generated by thedecode_record!macro: a length check followed byptr::read_unalignedinto an owned copy of the struct, orNoneif the payload is too short.read_unalignedis used because a payload slice carries no alignment guarantee even though the struct wants 64.
Runtime
None. The records are unaware of which path (UDP, TCP, disk) carries them; producers and consumers in the wider exchange own the runtime and transport decisions.
Benchmarks
no benchmark report yet for this crate.
Comparisons
no external comparison yet.