Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
cache-dependency-path: examples/guest_assemblyscript/package-lock.json
- uses: actions-rust-lang/setup-rust-toolchain@9d7e65c320fdb52dcd45ffaa68deb6c02c8754d9 # v1.10.1
with:
toolchain: stable
Expand All @@ -98,6 +103,12 @@ jobs:
run: cargo build --release --target wasm32-unknown-unknown --manifest-path examples/distributed_chat/Cargo.toml
- name: Build vote_tally_tls
run: cargo build --release --target wasm32-unknown-unknown --manifest-path examples/vote_tally_tls/Cargo.toml
- name: Build and test AssemblyScript guest
working-directory: examples/guest_assemblyscript
run: |
npm ci
npm run build
npm test

cli-smoke:
name: CLI Multi-process Smoke
Expand Down
3 changes: 3 additions & 0 deletions examples/guest_assemblyscript/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules/
guest.wasm
guest.wat
55 changes: 55 additions & 0 deletions examples/guest_assemblyscript/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# AssemblyScript guest

This example calls the raw Numax WebAssembly ABI from AssemblyScript. It exports
`run`, imports `nx.host_log_v2`, and logs `Hello from AssemblyScript!`.

The example was tested with Node.js 22 and AssemblyScript 0.28.8. The compiler is
pinned in `package-lock.json`, so no global AssemblyScript installation is needed.

## Build and test

From this directory:

```sh
npm ci
npm run build
npm test
```

The build produces `guest.wasm` and a readable `guest.wat`. The smoke test checks
the module's imports and exports, instantiates it with a small JavaScript host, and
asserts the exact logged message.

## Run with Numax

Build the CLI from the repository root:

```sh
cargo build --release -p nx-cli
```

Then return to this directory and run:

```sh
../../target/release/nx run guest.wasm
```

The output includes:

```text
Hello from AssemblyScript!
```

## ABI notes

Numax logging uses a pointer and byte length into the guest's exported linear
memory. The message is therefore stored as static UTF-8 bytes with
`memory.data<u8>` and passed directly to `host_log_v2`.

Using `String.UTF8.encode` would allocate managed AssemblyScript memory and pull
in the standard `env.abort` import for allocation checks. Numax does not provide
that namespace, so this deliberately minimal guest uses static data and imports
only `nx.host_log_v2`.

This is a raw ABI example, not a generated AssemblyScript binding. The resulting
module does not depend on WASI; Node.js and npm are only build and test tools.
13 changes: 13 additions & 0 deletions examples/guest_assemblyscript/asconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"targets": {
"release": {
"outFile": "guest.wasm",
"textFile": "guest.wat",
"runtime": "stub",
"optimizeLevel": 3,
"shrinkLevel": 0,
"converge": false,
"noAssert": true
}
}
}
12 changes: 12 additions & 0 deletions examples/guest_assemblyscript/assembly/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
@external("nx", "host_log_v2")
declare function hostLogV2(message: usize, length: i32): i32;

const MESSAGE = memory.data<u8>([
72, 101, 108, 108, 111, 32, 102, 114, 111, 109, 32, 65, 115, 115, 101, 109, 98, 108, 121, 83,
99, 114, 105, 112, 116, 33,
]);
const MESSAGE_LENGTH: i32 = 26;

export function run(): void {
hostLogV2(MESSAGE, MESSAGE_LENGTH);
}
61 changes: 61 additions & 0 deletions examples/guest_assemblyscript/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions examples/guest_assemblyscript/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "numax-guest-assemblyscript",
"private": true,
"scripts": {
"build": "asc assembly/index.ts --config asconfig.json --target release",
"test": "node test.mjs"
},
"devDependencies": {
"assemblyscript": "0.28.8"
}
}
36 changes: 36 additions & 0 deletions examples/guest_assemblyscript/test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";

const wasm = await readFile(new URL("./guest.wasm", import.meta.url));
const module = await WebAssembly.compile(wasm);

assert.deepEqual(WebAssembly.Module.imports(module), [
{ module: "nx", name: "host_log_v2", kind: "function" },
]);
assert.ok(
WebAssembly.Module.exports(module).some(
({ name, kind }) => name === "memory" && kind === "memory",
),
);
assert.ok(
WebAssembly.Module.exports(module).some(
({ name, kind }) => name === "run" && kind === "function",
),
);

let memory;
const messages = [];
const instance = await WebAssembly.instantiate(module, {
nx: {
host_log_v2(pointer, length) {
messages.push(
new TextDecoder().decode(new Uint8Array(memory.buffer, pointer, length)),
);
return 0;
},
},
});
memory = instance.exports.memory;
instance.exports.run();

assert.deepEqual(messages, ["Hello from AssemblyScript!"]);
Loading