https://github.com/yumin-chen/wasm-rust
Rust-to-WebAssembly compilation system that makes Rust truly WASM-native, not merely a language that targets WebAssembly.
https://github.com/yumin-chen/wasm-rust
rust rust-to-wasm webassembly
Last synced: 7 days ago
JSON representation
Rust-to-WebAssembly compilation system that makes Rust truly WASM-native, not merely a language that targets WebAssembly.
- Host: GitHub
- URL: https://github.com/yumin-chen/wasm-rust
- Owner: yumin-chen
- Created: 2025-12-29T06:37:57.000Z (6 months ago)
- Default Branch: main
- Last Pushed: 2025-12-30T10:37:47.000Z (6 months ago)
- Last Synced: 2026-01-10T18:19:59.820Z (5 months ago)
- Topics: rust, rust-to-wasm, webassembly
- Language: Rust
- Homepage:
- Size: 317 KB
- Stars: 1
- Watchers: 0
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: ReadMe.md
Awesome Lists containing this project
README
# WasmRust — Rust-to-WebAssembly Compiler
**WasmRust** is a research-driven, production-oriented Rust-to-WebAssembly compilation system. It aims to make **Rust truly WASM-native**, not merely a language that targets WebAssembly.
WasmRust extends Rust through **minimal, evidence-based compiler and library enhancements**, closing gaps in binary size, compilation speed, component interoperability, and host friction — all while preserving Rust’s safety guarantees. The focus of WasmRust is on **compilation correctness, binary size, and iteration speed**.
> **Core Principle:**
> WasmRust = rustc + WASM specialization, not a new language.
---
## ✨ Motivation
Despite Rust’s dominance in the WASM ecosystem (`wasmtime`, `wasmer`, `wit-bindgen`), developers face:
* **Large binaries** – even simple programs can be 35 KB; alternative WASM-first languages can be smaller.
* **Slow compilation** – LLVM backend + borrow checking slows iteration.
* **JS interop friction** – glue layers add overhead and complexity.
* **Steep learning curve** – ownership and lifetimes can be barriers.
* **WASM Component Model misalignment** – Rust semantics do not always map cleanly to WASM interfaces.
WasmRust asks:
> *What would Rust look like if WASM were a first-class execution model?*
---
## What Is WasmRust?
WasmRust is a **specialized Rust toolchain** that keeps the Rust frontend unchanged (parser, HIR, MIR, borrow checker) and augments code generation for WASM, providing library-level primitives that map directly to WASM concepts.
```text
┌─────────────────────────────────────────────┐
│ rustc frontend │
│ (parsing, HIR, MIR, borrow checking) │
│ UNCHANGED │
└───────────────────┬─────────────────────────┘
▼
┌─────────────────────────────────────────────┐
│ WASM-specialized codegen │
│ ┌────────────────┬────────────────────┐ │
│ │ Cranelift WASM │ LLVM WASM │ │
│ │ (dev builds) │ (release builds) │ │
│ └────────────────┴────────────────────┘ │
└─────────────────────────────────────────────┘
▼
┌─────────────────────────────────────────────┐
│ crates/wasm (zero-cost APIs) │
│ externref, threads, components, memory │
└─────────────────────────────────────────────┘
```
---
## 🌍 Design Philosophy
1. **WASM-native semantics**: Model WebAssembly concepts (memory, resources, components) directly.
2. **Safety without bloat**: Retain Rust’s memory safety while avoiding unnecessary runtime overhead.
3. **Incremental adoption**: Interoperate with existing Rust, `wasm-bindgen`, and WASI code.
4. **Global and federated**: Avoid centralized registries and vendor lock-in.
5. **Evidence-driven**: Features are justified through benchmarks, size, or correctness.
---
## 🏗 Architecture Overview
WasmRust is structured as a **five-layer stack**:
- Layer 5 — **Tooling & Ecosystem**: Registries, debugging, profiler
- Layer 4 — **Compiler**: WasmIR, Cranelift, LLVM, PGO
- Layer 3 — **Runtime Semantics**: Multi-memory, regions, threads
- Layer 2 — **Component Model**: WIT-native imports/exports
- Layer 1 — **Core Language** Linear types, effects, concurrency
---
### The 5 Layers in Detail
#### Layer 1 — Core Language Extensions & `crates/wasm`
The foundation of WasmRust is the `crates/wasm` library. It is `no_std`, dependency-free, runtime-free, and compiler-agnostic. Most WASM semantics belong at the library boundary, providing the compiler with semantic hooks for optimization and allowing stable Rust users to adopt WASM-first APIs today.
* **Linear Types**: Enforce use-once semantics for WASM resources to prevent leaks.
```rust
#[wasm::linear]
struct CanvasContext(wasm::Handle);
impl CanvasContext {
fn draw(&mut self) { /* ... */ }
// This consuming method moves ownership, preventing further use.
fn into_bitmap(self) -> ImageData { /* ... */ }
}
```
* **Structured Concurrency**: Scoped threads with automatic joining and lifetime-bound safety.
```rust
use wasm::thread::scope;
#[wasm::export]
fn parallel_transform(data: SharedSlice) -> Result<(), Error> {
scope(|s| {
for chunk in data.chunks(1000) {
s.spawn(|| process(chunk)); // Lifetime tied to scope
}
// All threads are automatically joined here
})?;
Ok(())
}
```
* **Effect System**: Track side effects like JS calls or I/O at the type level to enable optimizations like dead-effect elimination.
```rust
#[wasm::effect(js_call, atomic_read)]
fn fetch_and_cache(url: &str) -> Result, Error> {
let data = js::fetch(url)?;
CACHE.store(url, data);
Ok(data)
}
```
##### Why a Separate Crate?
* Most WebAssembly semantics are best expressed at the library level, not within the compiler.
* It allows for the explicit modeling of WebAssembly concepts, such as `externref`, shared memory, and components.
* It enables stable Rust users to adopt Wasm-first APIs today.
* It provides a semantic hook for the compiler to perform optimizations.
* This approach mirrors the evolution of `core`, `alloc`, and `std` as a set of layered abstractions.
* **Linear Types**: Enforce use-once semantics for WASM resources to prevent leaks.
```rust
#[wasm::linear]
struct CanvasContext(wasm::Handle);
impl CanvasContext {
fn draw(&mut self) { /* ... */ }
// This consuming method moves ownership, preventing further use.
fn into_bitmap(self) -> ImageData { /* ... */ }
}
```
* **Structured Concurrency**: Scoped threads with automatic joining and lifetime-bound safety.
```rust
use wasm::thread::scope;
#[wasm::export]
fn parallel_transform(data: SharedSlice) -> Result<(), Error> {
scope(|s| {
for chunk in data.chunks(1000) {
s.spawn(|| process(chunk)); // Lifetime tied to scope
}
// All threads are automatically joined here
})?;
Ok(())
}
```
* **Effect System**: Track side effects like JS calls or I/O at the type level to enable optimizations like dead-effect elimination.
```rust
#[wasm::effect(js_call, atomic_read)]
fn fetch_and_cache(url: &str) -> Result, Error> {
let data = js::fetch(url)?;
CACHE.store(url, data);
Ok(data)
}
```
#### Layer 2 — Component Model
Treats WIT as a first-class interface, enabling type-safe, bidirectional Rust ↔ WASM code generation without glue code.
```rust
#[wasm::wit]
interface crypto {
resource key-pair {
constructor(algorithm: string);
sign: func(data: bytes) -> bytes;
}
}
```
#### Layer 3 — Runtime Semantics
* **Multi-region memory**: First-class support for data residency and isolation.
* **Streaming compilation hints**: Optimize binary layout for faster Time-to-Interactive in browsers.
#### Layer 4 — Compiler Strategy
* **Cranelift-first dev builds** for fast iteration (~2s for 10k LOC).
* **LLVM release builds** for aggressive optimizations, `wasm-opt`, and Profile-Guided Optimization.
* **WasmIR**: A stable intermediate representation that captures linearity, reference types, and ownership invariants.
#### Layer 5 — Tooling & Ecosystem
* **Federated registries** to avoid centralized lock-in and geopolitical restrictions.
* **WASM-aware debugging tools** for memory visualization and inspection.
---
## Core Features
| Feature | Description |
| ----------------- | -------------------------------------------------------- |
| WASM-native types | `ExternRef`, `FuncRef`, `SharedSlice`, `Pod` |
| Linear types | Enforce move-only semantics for WASM resources |
| Component Model | Compiler-verified ABI, WIT bindings |
| JS Interop | Zero-copy, predictable boundary cost |
| Threading | Scoped concurrency, fallback in unsupported environments |
---
## Compilation Pipeline
```mermaid
graph LR
A[Rust Source] --> B[HIR/MIR]
B --> C[WasmIR]
C --> D{Build Profile}
D -->|Dev| E[Cranelift]
D -->|Release| F[LLVM]
E --> G[Fast WASM]
F --> H[Optimized WASM]
H --> I[wasm-opt]
I --> J[Component Wrapper]
```
**WasmIR** is a stable intermediate representation that encodes:
* Linear memory operations with bounds checking.
* Reference types (`externref`, `funcref`) with lifetime tracking.
* Component Model calling conventions.
* Capability annotations for optimization.
* Ownership and linearity invariants.
---
## Repository Structure
```
wasm-rust/
├── compiler/ # rustc extensions & backends
│ ├── codegen-cranelift/ # WASM-tuned Cranelift backend
│ ├── codegen-llvm/ # WASM-optimized LLVM backend
│ ├── verifier/ # Invariant checker pass [planned]
│ └── lints/ # wasm-recognition lint group [planned]
│
├── crates/
│ ├── wasm/ # Core zero-cost WASM abstractions
│ └── wasm-macros/ # Proc macros for Component Model / WIT [planned]
│
├── tooling/
│ └── cargo-wasm/ # WASM-aware Cargo frontend [planned]
│
├── docs/
│ ├── PRD-WasmRust.md # WasmRust Prouct Requirements Document
│ ├── TSD-WasmRust.md # WasmRust Technical Specification Document
│ ├── SAFETY.md # Unsafe invariants per type / crate
│ ├── compiler-contract.md # Formal compiler ↔ crate contracts
│ ├── RFCs/
│ └── architecture/
│
└── ReadMe.md
```
> Each crate has its own `ReadMe.md` and `Safety.md` files that describe its unsafe invariants and compiler contracts.
---
## Incremental Adoption
#### What Works Without WasmRust?
Everything in `crates/wasm`: it compiles on **stable Rust**, produces valid WASM, and has no dependency on a custom compiler. WasmRust **enhances**, but does not gate, functionality.
#### What Requires the WasmRust Compiler?
Native Component Model emission, Cranelift-accelerated builds, and advanced optimizations like PGO and WASM-aware thin monomorphization. These cannot be achieved from a library alone.
---
## Contracts & Governance
* **Language Surface Contract**: Core (80%): Standard Rust; Extensions (15%): `wasm` crate; Plugins (4%): `-Z` flags; Hard Fork (<1%): Minimal changes if required. Should upstream Rust introduce conflicting changes, a six-month deprecation window with automatic migration tools will be provided.
* **Compiler ↔ Crate Contract**: The WasmRust compiler assumes certain invariants when compiling code that uses `crates/wasm`. Unsafe operations must maintain these invariants, which are documented in `SAFETY.md`. The `wasm-recognition` lint group will detect misuses. Key invariants include:
* `ExternRef` and `FuncRef` are opaque handles with valid lifetime markers.
* `SharedSlice` contains only `Pod` types; aliasing and bounds are enforced.
* Linear types (`#[wasm::linear]`) follow move semantics; the compiler assumes no implicit copies.
* Component imports/exports use WIT-derived types; the ABI must match exactly.
* **Governance & Direction**:
* Upstream-friendly design.
* Library APIs stabilize before compiler features.
* Avoids ecosystem fragmentation.
* RFC-driven feature evolution.
---
## Notes on SAFETY.md
* Contains **formal unsafe invariants** per type.
* Used by the compiler **verifier pass** and **lint group**.
* Serves as authoritative documentation for both crate users and compiler developers.
---
## Host Profile Support
| Host Profile | Threading | JS Interop | Component Model | Memory Regions |
| ------------ | ----------------------------- | --------------- | --------------- | -------------- |
| Browser | SharedArrayBuffer + COOP/COEP | Direct calls | Partial | No |
| Node.js | Worker threads | Native bindings | Polyfill | No |
| Wasmtime | wasi-threads | Host functions | Full | Configurable |
| Embedded | No | No | Partial | No |
> Performance guarantees apply only to supported profiles.
---
## Testing and Verification
* Property-Based Testing: binary size, monomorphization, ownership enforcement, threading safety.
* Cross-Language ABI Testing: Zig, C, and other WASM components.
* Reproducible Builds and Performance Benchmarks.
---
## Comparative Snapshot
| Metric | WasmRust | Rust+bindgen | Zig | AssemblyScript |
| --------------- | ----------- | ------------ | ----- | -------------- |
| Binary size | ~2 KB | ~35 KB | ~1 KB | ~8 KB |
| Compile time | ~3s | ~12s | ~2s | ~4s |
| Memory safety | ✅ | ✅ | ⚠️ | ⚠️ |
| Component Model | ✅ | ❌ | ⚠️ | ❌ |
| Thread Safety | ✅ | ⚠️ Unsafe | ⚠️ | ⚠️ |
---
## 🚀 Roadmap
**Phase 1 — Proof of Concept (3 months)**
* `wasm` crate: core WASM abstractions
* Cranelift backend for dev builds
* Benchmark comparisons
**Phase 2 — Component Model (6 months)**
* WIT ↔ Rust bidirectional codegen
* `cargo-wasm` with federated registry
* DevTools memory visualization
**Phase 3 — Standardization (12 months)**
* RFCs for Layer 1 features
* Collaboration with Bytecode Alliance
* W3C WebAssembly CG presentation
---
## Non-Goals
* A Rust fork or new language
* Replacing `wasm-bindgen` initially
* A JavaScript framework or runtime
---
## Where to Start
* 📦 Use `crates/wasm` for low-level WASM code today.
* 📖 Read tech specs in [`docs/TSD-WasmRust.md`](docs/TSD-WasmRust.md).
* 🧪 Experiment with Cranelift WASM builds (nightly).
* 🛠️ Contribute to core abstractions before compiler work.