Skip to content

Latest commit

 

History

History
201 lines (152 loc) · 7.36 KB

File metadata and controls

201 lines (152 loc) · 7.36 KB

Rust Backend

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 service Rust crate
no Http effects aver-rt = { version = "=0.2.1" }
Http effects present aver-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:

Feature Status
Arithmetic, comparisons, string interpolation OK
match with all pattern types OK
Result<T,E>, Option<T> constructors + match OK
User-defined sum types (type Shape) OK
User-defined records (record User) OK
Record update (User.update(u, field = val)) OK
List literals, List.* operations OK
Map literals, Map.* operations OK
Tuple literals, tuple patterns OK
Error propagation (?) OK
Auto-memoization OK
Tail-call optimization OK
Module imports (depends [X]) OK
Console service OK
Http service OK
HttpServer service (listen, listenWith) OK
Tcp service (persistent connections) OK
Disk service OK
Env service OK
Random service OK
Time service OK
Terminal service (feature-gated) OK
Args service OK
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