Skip to content

feat: connection handshake — Client::connect / Server::serve_handshaked - #8

Merged
Kinflou merged 1 commit into
mainfrom
feat/runtime-handshake
Sep 1, 2026
Merged

feat: connection handshake — Client::connect / Server::serve_handshaked#8
Kinflou merged 1 commit into
mainfrom
feat/runtime-handshake

Conversation

@Kinflou

@Kinflou Kinflou commented Sep 1, 2026

Copy link
Copy Markdown
Member

Before any calls, each end declares { ir_hash, wire_format, framing, capabilities } and refuses on a mismatch — catches "one end MessagePack, one end JSON" and two ends built from different schema versions (§4.6).

contract::Handshake

Lifetime-free, Copy. wire_format / framing are carried as name_hash (FNV-1a) of a name, not a numeric id — a user's add-on WireFormat picks a namespaced name ("com.acme.myformat") and its hash won't collide with a built-in; no central id registry. Fixed 31-byte frame: [magic:2][ver:1][ir_hash:u64][wire_format:u64][framing:u64][caps:u32]. Handshake::new(ir_hash, wire_format_name, framing_name, caps) does the hashing.

  • WireFormat::name() -> &'static str (MsgPack"msgpack"); contract::FRAMING_DATAGRAM.
  • RuntimeError::Handshake (the enum is #[non_exhaustive], so additive).

The two modes

handshake
Client::connect(t, fmt, local) -> Result<Self, _> / Server::serve_handshaked(t, local) send ours, read + check the peer's, then proceed
Client::new / Server::serve skip it — "misaligned mode", documented, for legacy peers that can't take part

check refuses on ir_hash / wire_format / framing disagreement; capability bits may differ.

Tests

tests/handshake_roundtrip.rs — matching handshakes connect and a call goes through; a schema-hash mismatch is refused before any call (both ends get RuntimeError::Handshake); misaligned mode skips it. Plus handshake.rs unit tests (encode/decode round-trip, name_hash determinism, truncated/foreign rejection). All feature configs green; no new clippy warnings.

Next

A codegen PR: the generator emits IR_HASH (from the frozen IR fingerprint) and a <Proto>Client::connect / <Proto>Dispatcher serve helper that fills in the Handshake.

Before any calls, each end declares { ir_hash, wire_format, framing,
capabilities } and refuses on a mismatch -- catches "one end msgpack, one
end JSON" and two ends built from different schema versions.

- contract::Handshake -- lifetime-free, Copy. wire_format / framing are
  carried as name_hash (FNV-1a) of a *name*, not a numeric id: a user's
  add-on WireFormat picks a namespaced name and its hash won't collide
  with a built-in, no central registry. Fixed 31-byte frame
  ([magic][ver][ir_hash u64][wire_format u64][framing u64][caps u32]).
  Handshake::new(ir_hash, wire_format_name, framing_name, caps) hashes.
- WireFormat::name() -> &'static str (was going to be id() -> u16;
  dropped). MsgPack -> "msgpack". contract::FRAMING_DATAGRAM.
- RuntimeError::Handshake (non_exhaustive, so additive).
- Client::connect(transport, format, local) -> Result<Self, _> and
  Server::serve_handshaked(transport, local): send ours, read + check the
  peer's, then proceed. Client::new / Server::serve are unchanged and
  skip it entirely -- "misaligned mode", documented, for legacy peers.
- BufMut::put_u32_le.

tests/handshake_roundtrip.rs: matching handshakes connect + a call goes
through; a schema-hash mismatch is refused before any call (both ends);
misaligned mode skips it. Plus handshake.rs unit tests. All feature
configs green.

Generated code supplies IR_HASH and calls Client::connect -- a follow-up
codegen PR.
@Kinflou
Kinflou merged commit 3689cfd into main Sep 1, 2026
6 checks passed
@Kinflou
Kinflou deleted the feat/runtime-handshake branch September 1, 2026 19:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant