rustygo
A Go → Rust compiler. Compile Go packages into Rust source, link them with
a Rust runtime, and end up with Go and Rust code in one binary that share
real types — no cgo, no FFI, no unsafe in anything you write.
Status: scaffolding, M0 starting. The front end loads Go packages into SSA, and the runtime has its first pieces (Go integer semantics, builtin
println, panics). No Go code compiles to Rust yet. The plan is docs/DESIGN.md for the architecture, docs/RATIONALE.md for why this shape and not another, and docs/ROADMAP.md for the milestones.
Why
Two stacks that need each other:
- A large body of Go — cloud infrastructure, services, protocol libraries.
- A fast-growing body of pure Rust — purecrypto, compcol, graphitesql, OxideAV.
Today they are bridged by hand: tss-lib / tsslib-rs, outscript /
outscript-rs, spotlib / spotlib-rs, strtotime / strtotime-rs, gotz /
timezone-data-rs. Every pair is two implementations of one idea, kept
wire-compatible by discipline and test vectors.
rustygo attacks that from the other side: if Go compiles to Rust, a Go package can call a Rust crate directly, a Rust program can call a Go package directly, and there is one implementation again.
It also puts Go where only Rust currently goes: fullrust
static binaries, purestd libc-free
userland, kintane, no_std targets.
What it is not
- Not a source-to-source beautifier. The output is Rust that
rustccompiles, not Rust a human would enjoy reading. - Not a cgo replacement. Programs that need C are out of scope; that is the point.
- Not a Go implementation in Rust. The front end is Go's own
go/ssa; the Go compiler is not forked. - Not
GOARCH=rustin the gc toolchain. See docs/RATIONALE.md.
Shape
Go packages ──► go/packages + go/types ──► go/ssa
│
rustygo code generator
│
┌──────────────────────┴──────────────────────┐
▼ ▼
generated Rust crate(s) `rustygo` crate (runtime)
(safe Rust, no unsafe) GC · scheduler · chan · map ·
│ reflect · syscall shims
└──────────────────┬──────────────────────────┘
▼
rustc
│
native · fullrust · purestd · no_std subset
Generated code stays safe Rust. The unsafe lives in the runtime crate — the
garbage collector and the coroutine context switch — the same way Rust's own
std confines it.
type Point struct
func (k int)
// no pointers inside
The four hard parts
| Problem | Plan |
|---|---|
Garbage collection — Go has cycles, interior pointers (&s.f, &a[i]), slices sharing a backing array |
Precise tracing collector in the runtime; Gc<T> handles; generated trace impls; safe points at calls and loop back-edges; fat pointers for interior pointers |
Goroutines — can block anywhere, so async would colour nearly every function |
Stackful coroutines in the runtime (per-arch context switch), M:N scheduler, lazily committed fixed stacks |
reflect / unsafe.Pointer — encoding/json, fmt, much of the stdlib |
Emit full type descriptors; map unsafe.Pointer onto the runtime object model; document the patterns that will not be supported |
Standard library — assembly, go:linkname, runtime internals |
Compile the real stdlib with the purego build tag; reimplement only runtime, syscall, os bottom, reflect internals, sync/atomic on Rust std |
Details and the smaller traps (non-UTF-8 strings, randomized map order, nil and
divide-by-zero panics, defer/recover on Rust unwinding) are in
docs/DESIGN.md.
Honest cost
This is a TinyGo-sized project. TinyGo took years and several people, and still
does not cover all of reflect or the standard library. rustygo carries the
same weight plus a garbage collector Rust does not give it for free.
There is no cheaper path to the same goal. The WASM routes — running Rust inside Go on a WASM runtime, or compiling Go to WASM and translating that to Rust — are ruled out: they cost too much performance, and they cut the code off from native resources (threads, syscalls, devices, hardware acceleration) that both stacks exist to use. Native compilation is the requirement, so the runtime work below is the price of entry. docs/RATIONALE.md records the comparison.
Repository layout
One repository and one version number, with two halves:
| Path | What | Language |
|---|---|---|
cmd/rustygo, internal/ |
the compiler: rustygo build / emit / test / ssa |
Go (it runs on go/ssa) |
Cargo.toml, src/ |
the runtime: the rustygo crate generated code links against |
Rust |
docs/ |
design, rationale, roadmap |
The runtime is a single crate. Its optional parts are cargo features (std,
gc-torture, and more to come), not separate crates. Tracing code is written
by the emitter, not by a derive macro, so no proc-macro crate is needed.
Rust MSRV is 1.89 (edition 2024). The compiler targets the Go release pinned in
go.mod.
License
MIT. Copyright © 2026 Karpelès Lab Inc.