Rust port of singchia/geminio — one connection, bidirectional RPC, acknowledged messaging, and stream multiplexing behind a single async Conn.
Status: 0.1.0-dev — active pre-1.0 port. The core stack is in place: packet codecs, TCP transport, handshake, heartbeat, connection FSM, multiplexer/dialogue FSM, application
End/Stream, bidirectional RPC, acknowledged messaging, and Go↔Rust interop coverage. The upstream Go implementation atv1.3.0-rc.2remains the reference for behavior and wire format.
Go's geminio leans hard on goroutines + channels + GC for teardown coordination. Every bug we've fixed under chaos testing (send-on-closed-channel, nil-pointer after fini(), Write vs Close races) is a class of bug that Rust's ownership model turns into compile errors.
Trade-off: more explicit lifetime management, more verbose handler signatures. Upside: the race-detector flakes that motivated the go-timer fix in v1.3.0-rc.2 simply can't compile.
geminio-rs/
├── Cargo.toml # workspace root
├── Cargo.lock # committed (lib + bin reproducibility)
├── rust-toolchain.toml # Rust toolchain pin (1.90)
├── rustfmt.toml / clippy.toml # style + lint config
├── deny.toml # cargo-deny: licenses + advisories
├── .editorconfig
├── .github/workflows/
│ ├── ci.yml # check / fmt / clippy / test (3 OS) / doc
│ └── audit.yml # cargo-deny on Cargo.toml change + weekly cron
├── crates/ # workspace members
│ ├── geminio/ # public facade — what downstream depends on
│ ├── conn/ # Connection: transport, heartbeat, FSM
│ ├── mux/ # Multiplexer / Dialogue: logical streams, routing
│ └── app/ # Application: End, Stream, RPC, messaging
├── tools/
│ ├── interop/ # Go helper for cross-language tests
│ └── file_stream_server/ # Go server example for Rust-client file receive
├── README.md # this file
├── CHANGELOG.md # Keep a Changelog
├── CONTRIBUTING.md # workflow + style rules
└── ROADMAP.md # vertical slices toward Go v1.3.x parity
The three internal crates (conn / mux / app) are dropped of the geminio- prefix because the workspace itself already says geminio. The public geminio crate re-exports them so downstream code only needs one dependency:
use geminio::{End, Stream}; // app facade
use geminio::conn::Conn; // if you need the lower layer
use geminio::mux::Dialogue; // dittoThe Go ↔ Rust mapping:
| Go package | Rust crate |
|---|---|
github.com/singchia/geminio/conn |
crates/conn |
github.com/singchia/geminio/multiplexer |
crates/mux |
github.com/singchia/geminio/application |
crates/app |
github.com/singchia/geminio (top-level) |
crates/geminio |
Each crate's src/ mirrors the Go-side decomposition (packet/, transport/, fsm.rs, heartbeat.rs, etc.) so a reader who knows the Go side can navigate by symbol.
cargo check --workspace
cargo test --workspace --all-targets
cargo bench -p geminio --bench throughput # criterion benches
cargo run -p geminio --example smoke # raw packet demo
cargo run -p geminio --example rpc_echo # bidirectional RPC
cargo run -p geminio --example pubsub # acknowledged messaging
cargo run -p geminio --example stream_loopback # AsyncRead+Write Stream
cargo run -p geminio --example recv_file_from_go # Rust client receiving from Go server
make interop # Go ↔ Rust wire-compat testsrpc/16 ~74 µs/iter ~13.5K ops/sec
rpc/256 ~77 µs/iter ~13.0K ops/sec 3.2 MiB/s
rpc/4096 ~87 µs/iter ~11.5K ops/sec 45 MiB/s
publish/16 ~73 µs/iter
publish/4096 ~80 µs/iter 49 MiB/s
open_dialogue ~30 µs/iter
Each call/publish currently opens a fresh dialogue (full Session handshake + Dismiss); a dialogue-pooling pass is on the post-1.0 list.
- Workspace skeleton, layered traits.
- Project hygiene: CI, rustfmt, clippy, cargo-deny.
-
conn::packet: header + frame codec, byte-for-byte compatible with the Go wire format. -
conn::transport::tcp: framed read / framed write overtokio::net. -
conn: handshake, connection FSM, heartbeat, graceful close, TCPConndriver. -
mux: Session / Dismiss payloads, Dialogue FSM, open / dismiss handshake, routing, write scheduling. -
app: End, Stream (AsyncRead + AsyncWrite), bidirectional RPC, acknowledged messaging. - Cross-language interop: Go server ↔ Rust client and Rust server ↔ Go client RPC/publish checks.
- Hardening coverage: app lifecycle chaos, wire-level chaos, close-race tests, throughput benches.
- Full Go v1.3.x scenario parity audit.
- API freeze for 1.0 (
#[non_exhaustive]review, public surface cleanup). - Documented examples for every major Go-side example.
See ROADMAP.md for the full plan.
Apache-2.0 — same as the upstream Go implementation.