These libraries are experimental. APIs may change without notice. Generated from source with koruc 0.1.7 on 11/4/2026.
Enet
@korulang/enet@0.0.1Reliable + sequenced UDP sessions via libenet, behind phantom obligations
enet/index.kz · 18 tors
@korulang/enet — reliable + sequenced UDP sessions via libenet (v0: IPv4) · 30 more lines
@korulang/enet — reliable + sequenced UDP sessions via libenet (v0: IPv4)
Lifts ENet — the connection/channel/reliability layer ENet's own homepage
describes as "evolved specifically for Cube" — behind phantom obligations.
This is the transport SERVER_CHALLENGE.md names for the Cube 2 slice:
sequenced+reliable channels over UDP, connection lifecycle managed by the
library, one service call driving handshake/ping/resend.
1. There is no unbound-host state AT ALL. `host` (server) and `client`
are the only mints: a *Host exists only once it owns its socket.
2. `close` consumes <!host> — send-after-close is not expressible.
3. `service` fires `! connect` / `! packet` / `! disconnect` once per
ENet event, each a scoped borrow valid only inside its branch (the
udp `! packet` / raylib `! frame` shape). A borrow's release is
auto-inserted at the branch boundary — freeing the koru wrapper,
never the ENetPeer, which the library owns for the connection's life.
4. `peer.key` is the peer HANDLE as i64 — the column a server keys
per-client rows on (unlike udp's addr fold: a *ENetPeer cannot be
refolded from bytes, so the pointer IS the key). send.key casts it
back. Session rows drop on `! disconnect` — a stale key reaches a
recycled or dead peer slot, which is the named hazard below.
5. `dial` returns `| dialing` with the peer key immediately — the
outcome arrives later as a `! connect` on the client's own service,
symmetric with the server side. A blocking dial would deadlock a
loopback where the same thread must pump both hosts.
Service is a poll-shaped drain (timeout honored on the first event wait,
then drains queued events at 0): a server calls it once per tick, same
shape as libs/udp. The evented socket-source remains the shared named
gap (Orisha's kqueue pump is the port source).
Phantom lifecycles
Derived from the phantom labels in the declarations below — state! issues an
obligation the compiler will chase, !state discharges it, a bare state holds it without moving it. Nothing here is hand-drawn.
Host 1 state host!Peer 1 state peer!Packet 1 state packet!// Lifecycle — host (server) and client are the two mints, close the one exit.
//
// Bind a server host on 0.0.0.0:port. `down`/`up` are bandwidth caps in
// bytes/sec — 0 is unlimited, which is what a LAN or localhost server wants.
~pub tor host { port: u16, peers: i32, channels: i32, down: i32, up: i32 }
| up *Host<host!>
| err string// An unbound client host — one peer slot, ready to dial.
~pub tor client { channels: i32 }
| up *Host<host!>
| err string// Open a connection to ip:port. Returns the peer key NOW — the handshake
// completes asynchronously and arrives as `! connect` on this host's service.
// A server-side session row keys on the same value via peer.key.
~pub tor dial { host: *Host<host>, ip: string, port: u16, channels: i32 }
| dialing i64
| err string// Branchless: teardown cannot meaningfully fail, and an `| err` arm here
// would only fork the obligation graph (measured on udp's close, KORU030).
~pub tor close { host: *Host<!host> }// Service — the pump. Each call fires each queued event once; the three
// effect borrows are valid only inside their branch.
~pub tor service { host: *Host<host>, timeout_ms: i32 }
! connect *Peer<peer!>
! packet *Packet<packet!>
! disconnect *Peer<peer!>
| idle
| err string// Events — accessors. `peer.key` is the session-row column; `peer.pid` is
// enet's own incoming-peer index (the natural client-number slot).
~pub tor peer.key { p: *Peer<peer> } -> i64~pub tor peer.pid { p: *Peer<peer> } -> i64~pub tor packet.data { p: *Packet<packet> } -> string~pub tor packet.channel { p: *Packet<packet> } -> u8// The session key of the peer this packet arrived on — same value peer.key
// returns inside a ! connect / ! disconnect branch.
~pub tor packet.peer-key { p: *Packet<packet> } -> i64// The arriving peer's enet index — same as peer.pid off a live borrow.
~pub tor packet.peer-pid { p: *Packet<packet> } -> i64// Branch-boundary consumers, auto-inserted by phantom state name — free
// nothing, only discharge. One `release.peer` serves both ! connect and
// ! disconnect arms since both mint <peer!>.
~pub tor release.peer { p: *Peer<!peer> }~pub tor release.packet { p: *Packet<!packet> }// Sending — two spellings of the peer: the live borrow inside an effect
// branch, and the stored key from a session row.
~pub tor send.peer { p: *Peer<peer>, channel: u8, data: string, reliable: bool }
| sent
| err string~pub tor send.key {
host: *Host<host>,
key: i64,
channel: u8,
data: string,
reliable: bool
}
| sent
| err string// Graceful disconnect on the live borrow; the peer's `! disconnect` event
// still arrives through service — rows drop there, not here.
~pub tor peer.disconnect { p: *Peer<peer>, code: i32 }~pub tor peer.disconnect-key { host: *Host<host>, key: i64, code: i32 }// Push queued outgoing packets onto the wire without waiting for the next
// service pass.
~pub tor flush { host: *Host<host> }