Polyglot Genes —— 用 Rust、AssemblyScript、Go 或 C 写 Gene
Rotifer IR 协议层是 WASM-Native, Polyglot by Design(WASM 原生、生而多语言)。 CLI 当前内置一条 TypeScript → WASM 编译路径,走 Javy (QuickJS)。其他所有语言 —— Rust、AssemblyScript、Go(TinyGo)、C/C++、Zig —— 自己产出 WASM 后通过 Bring-Your-Own-WASM(BYO-WASM)通道接入:
# 1. 用任意工具链把 Gene 编译为 WASMwasm-pack build --target nodejs # Rustnpx asc index.ts --outFile gene.wasm # AssemblyScripttinygo build -target=wasi -o gene.wasm . # Goemcc gene.c -O3 -s STANDALONE_WASM -o gene.wasm # C / Emscripten
# 2. 把 WASM 交给 Rotifer CLIrotifer compile my-gene --wasm path/to/gene.wasmrotifer arena submit my-gene为什么可行。 Rotifer IR Specification §1.2 Rotifer IR 的定位 把 IR 定义为 语言无关的中间表示——多个语言前端 可以共同 target 它。CLI 的 Javy 路径只是众多前端之一。只要你的 WASM 遵守 下方的 ABI 契约,它就是一等公民 Rotifer Gene。
ABI 契约
Section titled “ABI 契约”你的 WASM 模块必须导出 以下两种之一 的入口加上 memory:
| 风格 | 必需导出 | 典型产生方式 |
|---|---|---|
| Rotifer | express(i32, i32) -> i32 + memory | Rust(#[no_mangle] extern "C")、AssemblyScript、Zig、手写 WAT |
| WASI | _start + memory(无参无返回) | 任何默认走 WASI 入口的语言 |
对于 Rotifer 风格,两个 i32 参数是 (input_ptr, input_len)——指向线性内存;
i32 返回值是打包后的 (output_ptr << 32) | output_len。Host 通过这个 buffer
读写 JSON。
WASI 风格更简单——适合 hello-world 级 fixture 和任何带内置 WASI runtime 的语言。
配方 1 —— Rust(wasm-pack / cargo)
Section titled “配方 1 —— Rust(wasm-pack / cargo)”Cargo.toml:
[package]name = "my-rotifer-gene"version = "0.1.0"edition = "2021"
[lib]crate-type = ["cdylib"]
[profile.release]lto = trueopt-level = "z"strip = truesrc/lib.rs:
#[no_mangle]pub extern "C" fn express(input_ptr: i32, input_len: i32) -> i32 { // 真实 Gene 的逻辑: // 1. 从线性内存 [input_ptr .. input_ptr + input_len] 读取 JSON 输入 // 2. 计算结果 // 3. 在内存里分配输出 buffer,返回打包的 (ptr, len) 0}构建并提交:
rustup target add wasm32-unknown-unknowncargo build --release --target wasm32-unknown-unknownrotifer compile my-rust-gene --wasm target/wasm32-unknown-unknown/release/my_rotifer_gene.wasmrotifer arena submit my-rust-gene可工作的最小 Rust 源码示例位于 playground 仓库
tests/fixtures/polyglot/rust-style/source/。
配方 2 —— AssemblyScript
Section titled “配方 2 —— AssemblyScript”AssemblyScript 是 TypeScript 开发者门槛最低的路径,产出的 WASM 比 Javy 小得多 (~10-50 KB vs ~700 KB)。
index.ts:
export function express(inputPtr: i32, inputLen: i32): i32 { // 真实 Gene 从内存读取输入、计算、返回打包后的 (ptr, len) return 0;}asconfig.json:
{ "targets": { "release": { "outFile": "gene.wasm", "optimize": true, "runtime": "stub" } }}构建并提交:
npm install --save-dev assemblyscriptnpx asc index.ts --target releaserotifer compile my-as-gene --wasm gene.wasmrotifer arena submit my-as-gene可工作的最小 AssemblyScript 源码位于
tests/fixtures/polyglot/as-style/source/。
配方 3 —— Go(TinyGo)
Section titled “配方 3 —— Go(TinyGo)”tinygo build -target=wasi -o gene.wasm ./gene.gorotifer compile my-go-gene --wasm gene.wasmTinyGo 产出 WASI 风格模块;IR 流水线通过 WASI ABI 接受它。注意
TinyGo 兼容性限制——大部分
Go 标准库可用,但重度依赖反射的包(encoding/json 处理任意类型、
text/template 等)可能不工作。
配方 4 —— C / C++(Emscripten)
Section titled “配方 4 —— C / C++(Emscripten)”emcc gene.c -O3 -s STANDALONE_WASM=1 -s EXPORTED_FUNCTIONS='["_express"]' -o gene.wasmrotifer compile my-c-gene --wasm gene.wasmSTANDALONE_WASM=1 是关键——没有它 Emscripten 会产出依赖 JavaScript runtime 的
胶水层,IR 沙箱不提供这个 runtime。
源语言检测与 --lang 覆盖
Section titled “源语言检测与 --lang 覆盖”rotifer publish 时,CLI 会把 Gene 的源语言写入 phenotype.sourceLanguage,
让 Registry 可以露出社区信号——“现在有多少非 TypeScript Gene?来自多少外部
贡献者?“——而不必扫描源码树。
自动检测(绝大多数项目无需 flag):
| Gene 目录中存在的文件 | 检测结果 |
|---|---|
index.ts 或 index.js | typescript |
Cargo.toml | rust |
assembly/index.ts 或 asconfig.json | assemblyscript |
go.mod | go |
*.c / *.cpp / *.cc / *.h / *.hpp | c |
仅有 gene.wasm(无源码) | external |
| 空目录或不识别的内容 | unknown |
源码优先于 gene.wasm:Cargo.toml + gene.wasm 解析为 rust 而非
external。
--lang 覆盖——当自动检测看不到真实工具链时(比如 Zig 项目只产出
gene.wasm,或者多语言 monorepo 想把 Gene 标记为 external 即使源文件
存在):
rotifer publish my-zig-gene --lang externalrotifer publish my-c-gene --lang c允许值:typescript / rust / assemblyscript / go / c /
external / unknown。无效值会在任何网络请求之前拒绝
publish——phenotype.sourceLanguage 是仪表盘唯一真相源,CLI 严格守门。
如果 phenotype.json 已经包含合法的 sourceLanguage 字段,它会优先于
自动检测(手动改一次后即可生效)。--lang 同时覆盖二者。
为什么重要。 这个信号会喂给一个内部仪表盘视图, 用于决定是否投入做内置 Rust / AssemblyScript 编译器。门槛是 外部 贡献者数 + 外部 Gene 占比——团队自己发布的 Gene 会被减掉。 所以诚实的语言声明直接影响非 TS 一等公民编译路径是否被优先排期。
当前状态:BYO-WASM 可用,内置编译路径正在评估中
Section titled “当前状态:BYO-WASM 可用,内置编译路径正在评估中”| 语言 | 状态 | 路径 |
|---|---|---|
| TypeScript | ✅ 内置(自动检测 index.ts) | esbuild + Javy/QuickJS |
| Rust | ✅ BYO-WASM | --wasm target/.../*.wasm |
| AssemblyScript | ✅ BYO-WASM | --wasm gene.wasm |
| Go(TinyGo) | ✅ BYO-WASM | --wasm gene.wasm(WASI ABI) |
| C / C++ | ✅ BYO-WASM | --wasm gene.wasm(STANDALONE_WASM) |
| Zig | ✅ BYO-WASM | --wasm gene.wasm |
| Python | ❌ 不可行(Pyodide ~10 MB 超过 WASM 燃料预算) | — |
是否把 Rust + AssemblyScript 从 BYO-WASM 升级为 内置编译路径 正在评估中。 触发是真实的社区需求——如果你需要这个能力,欢迎在 GitHub Issues 或 Discord 反馈。
为什么不支持 Python?
Section titled “为什么不支持 Python?”Python 在 WASM 中的 runtime 成本与单次调用的燃料预算不兼容:
- Pyodide(完整 CPython on WASM)~10 MB,仅模块实例化就耗尽燃料预算
- MicroPython-WASM(~1 MB)小到能跑,但标准库缺失,且没有支撑 AI/ML 的关键包
- CPython-WASI(3.12+,~3 MB)是最现实的选择,但仍是 Javy QuickJS 的 4 倍大
更关键的是,让 Python 在 AI 工作中具有吸引力的库(PyTorch、NumPy、Transformers) 是 C/Fortran 扩展,无法编译到 WASM。一个”Python Gene”只能表达纯 Python 业务逻辑——而这正是 TypeScript 已经覆盖的能力,且没有 runtime 开销。
对于 Python 重度的工作负载,应使用 Wrapped Gene:在 phenotype 中声明指向已有 Python 服务的元数据指针,让 Cloud Binding 执行它。组合模式见 Hybrid Gene 指南。
rotifer compile --wasm—— CLI 接口- Rotifer IR Specification §1.2 Rotifer IR 的定位 —— 语言无关 IR 设计
tests/fixtures/polyglot/—— 可运行的最小 WASM 模块和源码示例