A client and a server exchanging typed messages. We'll use the in-process pump so it runs without a socket; swapping in a real socket is one driver away (see runtime).
A channel is a stream with a reliability guarantee and a message type. The schema is a comptime value:
const magnet = @import("magnet");
const Chat = struct { from: u8, text: magnet.wire.Bounded(u8, 24) };
const Schema = magnet.proto.channels(.{
.chat = .{ .mode = .reliable_ordered, .Message = Chat },
.moves = .{ .mode = .unreliable_sequenced, .Message = struct { dx: i8, dy: i8 } },
});
const Channel = Schema.Channel; // a nominal enum unique to this schemaEverything derives from one Config. Defaults are sensible, so channels is often all
you set:
const Session = magnet.proto.Session(.{ .channels = Schema });This session is unencrypted.
security.modedefaults to.none, which is what makes the two-line setup above possible, but it authenticates nothing. Before you ship, set.security = .{ .mode = .aead }and assertcomptime magnet.validateProduction(Cfg), which turns a forgotten flag into a compile error rather than a production incident. Security covers the handshake, keys, and connect tokens.
send / receive are typed against the channel - the message is serialized for you:
var alice = Session{}; alice.init();
var bob = Session{}; bob.init();
try alice.send(.chat, .{ .from = 1, .text = .fromSlice("hello") });
// move datagrams from alice to bob (a real driver does this over a socket)
var buf: [1200]u8 = undefined;
while (alice.pollTransmit(&buf, 0)) |len| bob.feed(buf[0..len], 0);
while (bob.receive(.chat)) |m| std.debug.print("{d}: {s}\n", .{ m.from, m.text.slice() });The inferred .chat literal has type Schema.Channel, and it selects Chat as the only
accepted message type. See type safety for the deliberate generic and
raw-byte escape hatches.
That's the whole contract: feed bytes in, pollTransmit bytes out, send / receive
your messages. The session decides what to put on the wire and when; you decide how
the bytes travel.
- Many peers, not just two → an
Endpoint. - Run it over a real socket → runtime.
- Encrypt it → security.
- Sync a whole game world → replication.
Runnable: examples/echo.zig,
examples/typed_messages.zig.