Rust Backend

June 3, 2026 · View on GitHub

Rust is the deployment backend for Aver.

Use it when you want:

  • a native Cargo project
  • a normal Rust build/test/run loop
  • deployment without the Aver runtime

Quick start

aver compile examples/core/hello.av -o /tmp/hello-rs
cd /tmp/hello-rs && cargo build && cargo run

Output:

Compiled examples/core/hello.av → /tmp/hello-rs/ [Rust]
  cd /tmp/hello-rs && cargo build && cargo run

What it generates

Generates a complete Cargo project:

out/
  Cargo.toml
  src/
    main.rs
    runtime_support.rs
    aver_generated/
      mod.rs
      entry/
        mod.rs
      ...

The generated project includes:

  • src/main.rs with the runtime prelude and final entrypoint
  • src/runtime_support.rs for the shared aver-rt bridge and shared runtime types
  • src/replay_support.rs when --with-replay is enabled
  • src/aver_generated/.../mod.rs files that preserve the Aver module graph as Rust modules
  • src/verify.rs when the entry module has verify blocks

The generated Rust keeps:

  • user-defined types as Rust structs and enums inside their originating modules
  • direct depends [...] modules as explicit Rust imports inside generated module files
  • module-qualified Aver calls such as Domain.Tasks.replayTask(...) as qualified Rust paths
  • fn main() in src/main.rs delegating to aver_generated::entry::main()
  • #[cfg(test)] verify blocks as Rust tests for the entry module

src/main.rs includes:

  • runtime bridge (aver_rt module re-exporting the shared aver-rt crate)
  • shared runtime type imports for built-in service records when needed
  • the root aver_generated module tree
  • the final fn main() entry point

Generated Cargo projects now target Rust edition 2024.

Runtime dependency

Cargo.toml is generated around the shared aver-rt runtime crate. Service-specific runtime features are enabled only when needed:

Aver serviceRust crate
no Http effectsaver-rt = { version = "=0.2.1" }
Http effects presentaver-rt = { version = "=0.2.1", features = ["http"] }

ureq is pulled transitively by aver-rt/http; generated projects do not declare it directly.

For local runtime development from the Aver repository, set AVER_RUNTIME_PATH before running aver compile to force a path dependency instead of the crates.io release:

AVER_RUNTIME_PATH="$(pwd)/aver-rt" aver compile examples/core/hello.av -o /tmp/hello-rs

Scoped replay runtime

Use --with-replay when the generated binary should understand deterministic record/replay:

aver compile self_hosted/main.av \
  --module-root self_hosted \
  --with-replay \
  --guest-entry runGuestProgram \
  -o /tmp/aver-self

This emits src/replay_support.rs and adds the serde / serde_json / toml dependencies needed for recording files and guest-scoped runtime policy. Without --with-replay, generated projects stay smaller and do not carry replay support.

Use --with-self-host-support only for generated programs that are themselves self-host-like meta-runtimes and need SelfHostRuntime.* builtins such as the self-hosted HttpServer bridge:

aver compile self_hosted/main.av \
  --module-root self_hosted \
  --with-replay \
  --policy runtime \
  --guest-entry runGuestCliProgram \
  --with-self-host-support \
  -o /tmp/aver-self

This emits a separate src/self_host_support.rs module. It is intentionally not part of the generic generated runtime.

Generated Rust also exposes policy mode explicitly:

aver compile app.av --policy embed
aver compile app.av --policy runtime
  • --policy embed bakes the current aver.toml into the generated project
  • --policy runtime loads aver.toml from the active module root when the binary runs
  • default: embed for plain compile, runtime when --with-replay is enabled

--guest-entry matters for meta-runtimes such as the self-hosted interpreter:

  • bootstrap/tooling work stays outside record/replay and policy scope
  • only the chosen guest entry runs inside the scoped runtime
  • aver.toml policy and replay interception start at that boundary
  • policy is loaded at runtime from the guest module root instead of being baked into the binary

For --with-self-host-support, the chosen --guest-entry has an additional explicit contract:

  • it must declare prog: Program
  • it must declare moduleFns: List<FnDef>

Generated Rust uses those two parameters to install the temporary self-host callback store around the guest execution boundary. If the contract is not met, aver compile now fails early with a readable error instead of generating a broken project.

When the guest entry has a parameter named guestArgs: List<String>, generated replay support treats that parameter as the guest CLI input:

  • Args.get() inside the scoped guest run returns guestArgs
  • replay input records only guestArgs, not the outer wrapper arguments
  • self-host bootstrap args such as program_file and module_root stay outside the guest trace

SelfHostRuntime.* is also gated explicitly now:

  • if generated code uses SelfHostRuntime.*, aver compile requires --with-self-host-support
  • this detection includes top-level statements, not only function bodies

Supported features

All language features are transpilable:

FeatureStatus
Arithmetic, comparisons, string interpolationOK
match with all pattern typesOK
Result<T,E>, Option<T> constructors + matchOK
User-defined sum types (type Shape)OK
User-defined records (record User)OK
Record update (User.update(u, field = val))OK
List literals, List.* operationsOK
Map literals, Map.* operationsOK
Tuple literals, tuple patternsOK
Error propagation (?)OK
Tail-call optimizationOK
Module imports (depends [X])OK
Console serviceOK
Http serviceOK
HttpServer service (listen, listenWith)OK
Tcp service (persistent connections)OK
Disk serviceOK
Env serviceOK
Random serviceOK
Time serviceOK
Terminal service (feature-gated)OK
Args serviceOK
verify blocks → #[cfg(test)]OK
Exact method-level effects (Http.get, Disk.readText, etc.)OK

Running verify blocks

Verify blocks are emitted as #[test] functions:

aver compile examples/core/calculator.av -o /tmp/calc
cd /tmp/calc && cargo test

Module lowering

When a program has depends [Data.Fibonacci], the transpiler:

  1. loads the dependent .av file recursively, with circular import detection
  2. lowers each Aver module into a Rust module under src/aver_generated/...
  3. imports direct depends [...] modules explicitly in the generated Rust
  4. keeps qualified calls module-qualified: Data.Fibonacci.fib becomes crate::aver_generated::data::fibonacci::fib

This avoids the old giant single-file output and keeps medium projects reviewable in generated Rust.

Service runtime architecture

Generated Rust uses aver-rt as the shared runtime. The actual service implementations live there:

  • Tcp: shared aver-rt::tcp runtime with persistent connection map
  • Http: shared aver-rt::http client, enabled by the http feature
  • HttpServer: shared aver-rt::http_server loop and request/response types
  • Console, Time, Disk, Env, Args: shared helpers from aver-rt