Rust

  • Template: cart_rust - press "Use this template" and you have a working game.
  • Docker image: ghcr.io/notnullgames/null0-cart-rust:latest
  • Your code: cart/src/lib.rs, compiled with cargo, wasm32-unknown-unknown
  • Bindings: carts/rust/src/lib.rs (baked into the docker image for you)
  • WASI is available, so ordinary file and stdio calls work.
  • See carts made with Rust
  • API docs for Rust

building

You do not install cargo, wasm32-unknown-unknown - the docker image has it, and the current null0 bindings, baked in. There is nothing in your project to keep in sync with the engine.

docker run --rm --user $(id -u):$(id -g) \
  -v ./cart:/src -v ./webroot:/out \
  ghcr.io/notnullgames/null0-cart-rust:latest mygame

The template wraps that in npm start, which also serves the result and rebuilds when you save.

Rust notes

  • no_std, crate-type = ["cdylib"], panic = "abort".
  • The declarations live in an extern "C" block, so every call is unsafe.

a cart, in Rust

This is carts/rust/examples/simple/src/lib.rs in the engine repo - the same file CI builds into the cart below, so it always compiles.

#![no_std]

use null0::*;

#[no_mangle]
pub extern "C" fn load() {
    unsafe {
        clear(BLUE);
        draw_circle(100, 100, 50, RED);
        draw_text(FONT_DEFAULT, cstr!("hello from Rust"), 170, 92, WHITE);
    }
}

// callbacks (optional - implement as needed)
//
//   #[no_mangle]
//   pub extern "C" fn update() {}
carts/rust/examples/simple/src/lib.rs

callbacks

A cart implements the callbacks it cares about. In Rust they look like this:

#[no_mangle] pub extern "C" fn load() {}

See anatomy of a cart for the full list and what each one is passed.