feat: add a histrical wit-bindgen

This commit is contained in:
2023-01-01 00:25:48 +08:00
parent 01e8f5a959
commit aa50d63aec
419 changed files with 45283 additions and 1 deletions

View File

@@ -0,0 +1,4 @@
thunk: async func()
allocated-bytes: func() -> u32
test-concurrent: async func()

View File

@@ -0,0 +1,106 @@
import { addImportsToImports, Imports } from "./imports.js";
import { Exports } from "./exports.js";
import { getWasm, addWasiToImports } from "./helpers.js";
// @ts-ignore
import * as assert from 'assert';
function promiseChannel(): [Promise<void>, () => void] {
let resolveCallback = null;
const promise = new Promise((resolve, reject) => resolveCallback = resolve);
// @ts-ignore
return [promise, resolveCallback];
}
async function run() {
const importObj = {};
let hit = false;
const [concurrentPromise, resolveConcurrent] = promiseChannel();
const [unblockConcurrent1, resolveUnblockConcurrent1] = promiseChannel();
const [unblockConcurrent2, resolveUnblockConcurrent2] = promiseChannel();
const [unblockConcurrent3, resolveUnblockConcurrent3] = promiseChannel();
const imports: Imports = {
async thunk() {
if (hit) {
console.log('second time in thunk, throwing an error');
throw new Error('catch me');
} else {
console.log('first time in thunk');
await some_helper();
console.log('waited on the helper, returning from host thunk');
hit = true;
}
},
async concurrent1(val) {
console.log('wasm called concurrent1');
assert.equal(val, 1);
resolveUnblockConcurrent1();
console.log('concurrent1 to reenter back into the host');
await concurrentPromise;
console.log('concurrent1 returning to wasm');
return 11;
},
async concurrent2(val) {
console.log('wasm called concurrent2');
assert.equal(val, 2);
resolveUnblockConcurrent2();
console.log('concurrent2 to reenter back into the host');
await concurrentPromise;
console.log('concurrent2 returning to wasm');
return 12;
},
async concurrent3(val) {
console.log('wasm called concurrent3');
assert.equal(val, 3);
resolveUnblockConcurrent3();
console.log('concurrent3 to reenter back into the host');
await concurrentPromise;
console.log('concurrent3 returning to wasm');
return 13;
},
};
let instance: WebAssembly.Instance;
addImportsToImports(importObj, imports, name => instance.exports[name]);
const wasi = addWasiToImports(importObj);
const wasm = new Exports();
await wasm.instantiate(getWasm(), importObj);
wasi.start(wasm.instance);
instance = wasm.instance;
const initBytes = wasm.allocatedBytes();
console.log("calling initial async function");
await wasm.thunk();
assert.ok(hit, "import not called");
assert.equal(initBytes, wasm.allocatedBytes());
// Make sure that exceptions on the host make their way back to whomever's
// doing the actual `await`
try {
console.log('executing thunk export a second time');
await wasm.thunk();
throw new Error('expected an error to get thrown');
} catch (e) {
const err = e as Error;
console.log('caught error with', err.message);
assert.equal(err.message, 'catch me');
}
console.log('entering wasm');
const concurrentWasm = wasm.testConcurrent();
console.log('waiting for wasm to enter the host');
await unblockConcurrent1;
await unblockConcurrent2;
await unblockConcurrent3;
console.log('allowing host functions to finish');
resolveConcurrent();
console.log('waiting on host functions');
await concurrentWasm;
console.log('concurrent wasm finished');
}
async function some_helper() {}
await run()

View File

@@ -0,0 +1,5 @@
thunk: async func()
concurrent1: async func(a: u32) -> u32
concurrent2: async func(a: u32) -> u32
concurrent3: async func(a: u32) -> u32

View File

@@ -0,0 +1,23 @@
wit_bindgen_rust::import!("../../tests/runtime/async_functions/imports.wit");
wit_bindgen_rust::export!("../../tests/runtime/async_functions/exports.wit");
struct Exports;
#[wit_bindgen_rust::async_trait(?Send)]
impl exports::Exports for Exports {
fn allocated_bytes() -> u32 {
test_rust_wasm::get() as u32
}
async fn thunk() {
imports::thunk().await;
}
async fn test_concurrent() {
let a1 = imports::concurrent1(1);
let a2 = imports::concurrent2(2);
let a3 = imports::concurrent3(3);
assert_eq!(futures_util::join!(a2, a3, a1), (12, 13, 11));
}
}

View File

@@ -0,0 +1,31 @@
test-imports: func()
record list-in-record1 { a: string }
record list-in-record2 { a: string }
record list-in-record3 { a: string }
record list-in-record4 { a: string }
type list-in-alias = list-in-record4
list-in-record1: func(a: list-in-record1)
list-in-record2: func() -> list-in-record2
list-in-record3: func(a: list-in-record3) -> list-in-record3
list-in-record4: func(a: list-in-alias) -> list-in-alias
type list-in-variant1-v1 = option<string>
type list-in-variant1-v2 = expected<unit, string>
union list-in-variant1-v3 { string, float32 }
list-in-variant1: func(a: list-in-variant1-v1, b: list-in-variant1-v2, c: list-in-variant1-v3)
type list-in-variant2 = option<string>
list-in-variant2: func() -> list-in-variant2
type list-in-variant3 = option<string>
list-in-variant3: func(a: list-in-variant3) -> list-in-variant3
enum my-errno { success, a, b }
errno-result: func() -> expected<unit, my-errno>
type list-typedef = string
type list-typedef2 = list<u8>
type list-typedef3 = list<string>
list-typedefs: func(a: list-typedef, c: list-typedef3) -> tuple<list-typedef2, list-typedef3>

View File

@@ -0,0 +1,86 @@
from exports.bindings import Exports
from imports.bindings import add_imports_to_linker, Imports
from typing import Tuple, List
import exports.bindings as e
import imports.bindings as i
import sys
import wasmtime
class MyImports:
def list_in_record1(self, a: i.ListInRecord1) -> None:
pass
def list_in_record2(self) -> i.ListInRecord2:
return i.ListInRecord2('list_in_record2')
def list_in_record3(self, a: i.ListInRecord3) -> i.ListInRecord3:
assert(a.a == 'list_in_record3 input')
return i.ListInRecord3('list_in_record3 output')
def list_in_record4(self, a: i.ListInAlias) -> i.ListInAlias:
assert(a.a == 'input4')
return i.ListInRecord4('result4')
def list_in_variant1(self, a: i.ListInVariant1V1, b: i.ListInVariant1V2, c: i.ListInVariant1V3) -> None:
assert(a == 'foo')
assert(b == i.Err('bar'))
assert(c == 'baz')
def list_in_variant2(self) -> i.ListInVariant2:
return 'list_in_variant2'
def list_in_variant3(self, a: i.ListInVariant3) -> i.ListInVariant3:
assert(a == 'input3')
return 'output3'
def errno_result(self) -> i.Expected[None, i.MyErrno]:
return i.Err(i.MyErrno.B)
def list_typedefs(self, a: i.ListTypedef, c: i.ListTypedef3) -> Tuple[i.ListTypedef2, i.ListTypedef3]:
assert(a == 'typedef1')
assert(c == ['typedef2'])
return (b'typedef3', ['typedef4'])
def list_of_variants(self, a: List[bool], b: List[i.Expected[None, None]], c: List[i.MyErrno]) -> Tuple[List[bool], List[i.Expected[None, None]], List[i.MyErrno]]:
assert(a == [True, False])
assert(b == [i.Ok(None), i.Err(None)])
assert(c == [i.MyErrno.SUCCESS, i.MyErrno.A])
return (
[False, True],
[i.Err(None), i.Ok(None)],
[i.MyErrno.A, i.MyErrno.B],
)
def run(wasm_file: str) -> None:
store = wasmtime.Store()
module = wasmtime.Module.from_file(store.engine, wasm_file)
linker = wasmtime.Linker(store.engine)
linker.define_wasi()
wasi = wasmtime.WasiConfig()
wasi.inherit_stdout()
wasi.inherit_stderr()
store.set_wasi(wasi)
imports = MyImports()
add_imports_to_linker(linker, store, imports)
wasm = Exports(store, linker, module)
wasm.test_imports(store)
wasm.list_in_record1(store, e.ListInRecord1("list_in_record1"))
assert(wasm.list_in_record2(store) == e.ListInRecord2(a="list_in_record2"))
assert(wasm.list_in_record3(store, e.ListInRecord3("list_in_record3 input")).a == "list_in_record3 output")
assert(wasm.list_in_record4(store, e.ListInRecord4("input4")).a == "result4")
wasm.list_in_variant1(store, "foo", e.Err("bar"), 'baz')
assert(wasm.list_in_variant2(store) == "list_in_variant2")
assert(wasm.list_in_variant3(store, "input3") == "output3")
assert(isinstance(wasm.errno_result(store), e.Err))
r1, r2 = wasm.list_typedefs(store, "typedef1", ["typedef2"])
assert(r1 == b'typedef3')
assert(r2 == ['typedef4'])
if __name__ == '__main__':
run(sys.argv[1])

View File

@@ -0,0 +1,160 @@
use anyhow::Result;
wit_bindgen_wasmtime::export!("../../tests/runtime/flavorful/imports.wit");
use imports::*;
#[derive(Default)]
pub struct MyImports;
impl Imports for MyImports {
fn list_in_record1(&mut self, ty: ListInRecord1<'_>) {
assert_eq!(ty.a, "list_in_record1");
}
fn list_in_record2(&mut self) -> ListInRecord2 {
ListInRecord2 {
a: "list_in_record2".to_string(),
}
}
fn list_in_record3(&mut self, a: ListInRecord3Param<'_>) -> ListInRecord3Result {
assert_eq!(a.a, "list_in_record3 input");
ListInRecord3Result {
a: "list_in_record3 output".to_string(),
}
}
fn list_in_record4(&mut self, a: ListInAliasParam<'_>) -> ListInAliasResult {
assert_eq!(a.a, "input4");
ListInRecord4Result {
a: "result4".to_string(),
}
}
fn list_in_variant1(
&mut self,
a: ListInVariant1V1<'_>,
b: ListInVariant1V2<'_>,
c: ListInVariant1V3<'_>,
) {
assert_eq!(a.unwrap(), "foo");
assert_eq!(b.unwrap_err(), "bar");
match c {
ListInVariant1V3::String(s) => assert_eq!(s, "baz"),
ListInVariant1V3::F32(_) => panic!(),
}
}
fn list_in_variant2(&mut self) -> Option<String> {
Some("list_in_variant2".to_string())
}
fn list_in_variant3(&mut self, a: ListInVariant3Param<'_>) -> Option<String> {
assert_eq!(a.unwrap(), "input3");
Some("output3".to_string())
}
fn errno_result(&mut self) -> Result<(), MyErrno> {
MyErrno::A.to_string();
format!("{:?}", MyErrno::A);
fn assert_error<T: std::error::Error>() {}
assert_error::<MyErrno>();
Err(MyErrno::B)
}
fn list_typedefs(
&mut self,
a: ListTypedef<'_>,
b: ListTypedef3Param<'_>,
) -> (ListTypedef2, ListTypedef3Result) {
assert_eq!(a, "typedef1");
assert_eq!(b.len(), 1);
assert_eq!(b[0], "typedef2");
(b"typedef3".to_vec(), vec!["typedef4".to_string()])
}
fn list_of_variants(
&mut self,
bools: Vec<bool>,
results: Vec<Result<(), ()>>,
enums: Vec<MyErrno>,
) -> (Vec<bool>, Vec<Result<(), ()>>, Vec<MyErrno>) {
assert_eq!(bools, [true, false]);
assert_eq!(results, [Ok(()), Err(())]);
assert_eq!(enums, [MyErrno::Success, MyErrno::A]);
(
vec![false, true],
vec![Err(()), Ok(())],
vec![MyErrno::A, MyErrno::B],
)
}
}
wit_bindgen_wasmtime::import!("../../tests/runtime/flavorful/exports.wit");
fn run(wasm: &str) -> Result<()> {
use exports::*;
let (exports, mut store) = crate::instantiate(
wasm,
|linker| imports::add_to_linker(linker, |cx| -> &mut MyImports { &mut cx.imports }),
|store, module, linker| Exports::instantiate(store, module, linker, |cx| &mut cx.exports),
)?;
exports.test_imports(&mut store)?;
exports.list_in_record1(
&mut store,
ListInRecord1 {
a: "list_in_record1",
},
)?;
assert_eq!(exports.list_in_record2(&mut store)?.a, "list_in_record2");
assert_eq!(
exports
.list_in_record3(
&mut store,
ListInRecord3Param {
a: "list_in_record3 input"
}
)?
.a,
"list_in_record3 output"
);
assert_eq!(
exports
.list_in_record4(&mut store, ListInAliasParam { a: "input4" })?
.a,
"result4"
);
exports.list_in_variant1(
&mut store,
Some("foo"),
Err("bar"),
ListInVariant1V3::String("baz"),
)?;
assert_eq!(
exports.list_in_variant2(&mut store)?,
Some("list_in_variant2".to_string())
);
assert_eq!(
exports.list_in_variant3(&mut store, Some("input3"))?,
Some("output3".to_string())
);
assert!(exports.errno_result(&mut store)?.is_err());
MyErrno::A.to_string();
format!("{:?}", MyErrno::A);
fn assert_error<T: std::error::Error>() {}
assert_error::<MyErrno>();
let (a, b) = exports.list_typedefs(&mut store, "typedef1", &["typedef2"])?;
assert_eq!(a, b"typedef3");
assert_eq!(b.len(), 1);
assert_eq!(b[0], "typedef4");
Ok(())
}

View File

@@ -0,0 +1,85 @@
import { addImportsToImports, Imports, MyErrno } from "./imports.js";
import { Exports } from "./exports.js";
import * as exports from "./exports.js";
import { getWasm, addWasiToImports } from "./helpers.js";
// @ts-ignore
import * as assert from 'assert';
async function run() {
const importObj = {};
const imports: Imports = {
listInRecord1(x) {},
listInRecord2() { return { a: 'list_in_record2' }; },
listInRecord3(x) {
assert.strictEqual(x.a, 'list_in_record3 input');
return { a: 'list_in_record3 output' };
},
listInRecord4(x) {
assert.strictEqual(x.a, 'input4');
return { a: 'result4' };
},
listInVariant1(a, b, c) {
assert.strictEqual(a, 'foo');
assert.deepStrictEqual(b, { tag: 'err', val: 'bar' });
assert.deepStrictEqual(c, { tag: 0, val: 'baz' });
},
listInVariant2() { return 'list_in_variant2'; },
listInVariant3(x) {
assert.strictEqual(x, 'input3');
return 'output3';
},
errnoResult() { return { tag: 'err', val: "b" }; },
listTypedefs(x, y) {
assert.strictEqual(x, 'typedef1');
assert.deepStrictEqual(y, ['typedef2']);
return [(new TextEncoder).encode('typedef3'), ['typedef4']];
},
listOfVariants(bools, results, enums) {
assert.deepStrictEqual(bools, [true, false]);
assert.deepStrictEqual(results, [{ tag: 'ok', val: undefined }, { tag: 'err', val: undefined }]);
assert.deepStrictEqual(enums, ["success", "a"]);
return [
[false, true],
[{ tag: 'err', val: undefined }, { tag: 'ok', val: undefined }],
["a", "b"],
];
},
};
let instance: WebAssembly.Instance;
addImportsToImports(importObj, imports, name => instance.exports[name]);
const wasi = addWasiToImports(importObj);
const wasm = new Exports();
await wasm.instantiate(getWasm(), importObj);
wasi.start(wasm.instance);
instance = wasm.instance;
wasm.testImports();
wasm.listInRecord1({ a: "list_in_record1" });
assert.deepStrictEqual(wasm.listInRecord2(), { a: "list_in_record2" });
assert.deepStrictEqual(
wasm.listInRecord3({ a: "list_in_record3 input" }),
{ a: "list_in_record3 output" },
);
assert.deepStrictEqual(
wasm.listInRecord4({ a: "input4" }),
{ a: "result4" },
);
wasm.listInVariant1("foo", { tag: 'err', val: 'bar' }, { tag: 0, val: 'baz' });
assert.deepStrictEqual(wasm.listInVariant2(), "list_in_variant2");
assert.deepStrictEqual(wasm.listInVariant3("input3"), "output3");
assert.deepStrictEqual(wasm.errnoResult().tag, 'err');
const [r1, r2] = wasm.listTypedefs("typedef1", ["typedef2"]);
assert.deepStrictEqual(r1, (new TextEncoder()).encode('typedef3'));
assert.deepStrictEqual(r2, ['typedef4']);
}
await run()

View File

@@ -0,0 +1,31 @@
record list-in-record1 { a: string }
record list-in-record2 { a: string }
record list-in-record3 { a: string }
record list-in-record4 { a: string }
type list-in-alias = list-in-record4
list-in-record1: func(a: list-in-record1)
list-in-record2: func() -> list-in-record2
list-in-record3: func(a: list-in-record3) -> list-in-record3
list-in-record4: func(a: list-in-alias) -> list-in-alias
type list-in-variant1-v1 = option<string>
type list-in-variant1-v2 = expected<unit, string>
union list-in-variant1-v3 { string, float32 }
list-in-variant1: func(a: list-in-variant1-v1, b: list-in-variant1-v2, c: list-in-variant1-v3)
type list-in-variant2 = option<string>
list-in-variant2: func() -> list-in-variant2
type list-in-variant3 = option<string>
list-in-variant3: func(a: list-in-variant3) -> list-in-variant3
enum my-errno { success, a, b }
errno-result: func() -> expected<unit, my-errno>
type list-typedef = string
type list-typedef2 = list<u8>
type list-typedef3 = list<string>
list-typedefs: func(a: list-typedef, c: list-typedef3) -> tuple<list-typedef2, list-typedef3>
list-of-variants: func(a: list<bool>, b: list<expected<unit, unit>>, c: list<my-errno>) -> tuple<list<bool>, list<expected<unit, unit>>, list<my-errno>>

View File

@@ -0,0 +1,197 @@
#include <assert.h>
#include <imports.h>
#include <exports.h>
#include <stdlib.h>
#include <string.h>
void exports_test_imports() {
{
imports_list_in_record1_t a;
imports_string_set(&a.a, "list_in_record1");
imports_list_in_record1(&a);
imports_list_in_record2_t b;
imports_list_in_record2(&b);
assert(memcmp(b.a.ptr, "list_in_record2", b.a.len) == 0);
imports_list_in_record2_free(&b);
}
{
imports_list_in_record3_t a, b;
imports_string_set(&a.a, "list_in_record3 input");
imports_list_in_record3(&a, &b);
assert(memcmp(b.a.ptr, "list_in_record3 output", b.a.len) == 0);
imports_list_in_record3_free(&b);
}
{
imports_list_in_record4_t a, b;
imports_string_set(&a.a, "input4");
imports_list_in_record4(&a, &b);
assert(memcmp(b.a.ptr, "result4", b.a.len) == 0);
imports_list_in_record4_free(&b);
}
{
imports_list_in_variant1_v1_t a;
imports_list_in_variant1_v2_t b;
imports_list_in_variant1_v3_t c;
a.is_some = true;
imports_string_set(&a.val, "foo");
b.is_err = true;
imports_string_set(&b.val.err, "bar");
c.tag = 0;
imports_string_set(&c.val.f0, "baz");
imports_list_in_variant1(&a, &b, &c);
}
{
imports_string_t a;
assert(imports_list_in_variant2(&a));
assert(memcmp(a.ptr, "list_in_variant2", a.len) == 0);
imports_string_free(&a);
}
{
imports_list_in_variant3_t a;
a.is_some = true;
imports_string_set(&a.val, "input3");
imports_string_t b;
assert(imports_list_in_variant3(&a, &b));
assert(memcmp(b.ptr, "output3", b.len) == 0);
imports_string_free(&b);
}
assert(imports_errno_result() == IMPORTS_MY_ERRNO_B);
{
imports_string_t a;
imports_string_set(&a, "typedef1");
imports_string_t b_str;
imports_string_set(&b_str, "typedef2");
imports_list_typedef3_t b;
b.ptr = &b_str;
b.len = 1;
imports_list_typedef2_t c;
imports_list_typedef3_t d;
imports_list_typedefs(&a, &b, &c, &d);
assert(memcmp(c.ptr, "typedef3", c.len) == 0);
assert(d.len == 1);
assert(memcmp(d.ptr[0].ptr, "typedef4", d.ptr[0].len) == 0);
imports_list_typedef2_free(&c);
imports_list_typedef3_free(&d);
}
{
imports_list_bool_t a;
bool a_val[] = {true, false};
a.ptr = a_val;
a.len = 2;
imports_list_expected_unit_unit_t b;
imports_expected_unit_unit_t b_val[2];
b_val[0].is_err = false;
b_val[1].is_err = true;
b.ptr = b_val;
b.len = 2;
imports_list_my_errno_t c;
imports_my_errno_t c_val[2];
c_val[0] = IMPORTS_MY_ERRNO_SUCCESS;
c_val[1] = IMPORTS_MY_ERRNO_A;
c.ptr = c_val;
c.len = 2;
imports_list_bool_t d;
imports_list_expected_unit_unit_t e;
imports_list_my_errno_t f;
imports_list_of_variants(&a, &b, &c, &d, &e, &f);
assert(d.len == 2);
assert(d.ptr[0] == false);
assert(d.ptr[1] == true);
assert(e.len == 2);
assert(e.ptr[0].is_err == true);
assert(e.ptr[1].is_err == false);
assert(f.len == 2);
assert(f.ptr[0] == IMPORTS_MY_ERRNO_A);
assert(f.ptr[1] == IMPORTS_MY_ERRNO_B);
imports_list_bool_free(&d);
imports_list_expected_unit_unit_free(&e);
imports_list_my_errno_free(&f);
}
}
void exports_list_in_record1(exports_list_in_record1_t *a) {
assert(memcmp(a->a.ptr, "list_in_record1", a->a.len) == 0);
exports_list_in_record1_free(a);
}
void exports_list_in_record2(exports_list_in_record2_t *ret0) {
exports_string_dup(&ret0->a, "list_in_record2");
}
void exports_list_in_record3(exports_list_in_record3_t *a, exports_list_in_record3_t *ret0) {
assert(memcmp(a->a.ptr, "list_in_record3 input", a->a.len) == 0);
exports_list_in_record3_free(a);
exports_string_dup(&ret0->a, "list_in_record3 output");
}
void exports_list_in_record4(exports_list_in_alias_t *a, exports_list_in_alias_t *ret0) {
assert(memcmp(a->a.ptr, "input4", a->a.len) == 0);
exports_list_in_alias_free(a);
exports_string_dup(&ret0->a, "result4");
}
void exports_list_in_variant1(exports_list_in_variant1_v1_t *a, exports_list_in_variant1_v2_t *b, exports_list_in_variant1_v3_t *c) {
assert(a->is_some);
assert(memcmp(a->val.ptr, "foo", a->val.len) == 0);
exports_list_in_variant1_v1_free(a);
assert(b->is_err);
assert(memcmp(b->val.err.ptr, "bar", b->val.err.len) == 0);
exports_list_in_variant1_v2_free(b);
assert(c->tag == 0);
assert(memcmp(c->val.f0.ptr, "baz", c->val.f0.len) == 0);
exports_list_in_variant1_v3_free(c);
}
bool exports_list_in_variant2(exports_string_t *ret0) {
exports_string_dup(ret0, "list_in_variant2");
return true;
}
bool exports_list_in_variant3(exports_list_in_variant3_t *a, exports_string_t *ret0) {
assert(a->is_some);
assert(memcmp(a->val.ptr, "input3", a->val.len) == 0);
exports_list_in_variant3_free(a);
exports_string_dup(ret0, "output3");
return true;
}
exports_my_errno_t exports_errno_result(void) {
return EXPORTS_MY_ERRNO_B;
}
void exports_list_typedefs(exports_list_typedef_t *a, exports_list_typedef3_t *c, exports_list_typedef2_t *ret0, exports_list_typedef3_t *ret1) {
assert(memcmp(a->ptr, "typedef1", a->len) == 0);
exports_list_typedef_free(a);
assert(c->len == 1);
assert(memcmp(c->ptr[0].ptr, "typedef2", c->ptr[0].len) == 0);
exports_list_typedef3_free(c);
ret0->ptr = malloc(8);
ret0->len = 8;
memcpy(ret0->ptr, "typedef3", 8);
ret1->ptr = malloc(sizeof(exports_string_t));
ret1->len = 1;
exports_string_dup(&ret1->ptr[0], "typedef4");
}

View File

@@ -0,0 +1,116 @@
wit_bindgen_rust::import!("../../tests/runtime/flavorful/imports.wit");
wit_bindgen_rust::export!("../../tests/runtime/flavorful/exports.wit");
use exports::*;
struct Exports;
impl exports::Exports for Exports {
fn test_imports() {
use imports::*;
let _guard = test_rust_wasm::guard();
list_in_record1(ListInRecord1 {
a: "list_in_record1",
});
assert_eq!(list_in_record2().a, "list_in_record2");
assert_eq!(
list_in_record3(ListInRecord3Param {
a: "list_in_record3 input"
})
.a,
"list_in_record3 output"
);
assert_eq!(
list_in_record4(ListInAliasParam { a: "input4" }).a,
"result4"
);
list_in_variant1(Some("foo"), Err("bar"), ListInVariant1V3::String("baz"));
assert_eq!(list_in_variant2(), Some("list_in_variant2".to_string()));
assert_eq!(
list_in_variant3(Some("input3")),
Some("output3".to_string())
);
assert!(errno_result().is_err());
MyErrno::A.to_string();
format!("{:?}", MyErrno::A);
fn assert_error<T: std::error::Error>() {}
assert_error::<MyErrno>();
let (a, b) = list_typedefs("typedef1", &["typedef2"]);
assert_eq!(a, b"typedef3");
assert_eq!(b.len(), 1);
assert_eq!(b[0], "typedef4");
let (a, b, c) = list_of_variants(
&[true, false],
&[Ok(()), Err(())],
&[MyErrno::Success, MyErrno::A],
);
assert_eq!(a, [false, true]);
assert_eq!(b, [Err(()), Ok(())]);
assert_eq!(c, [MyErrno::A, MyErrno::B]);
}
fn list_in_record1(ty: ListInRecord1) {
assert_eq!(ty.a, "list_in_record1");
}
fn list_in_record2() -> ListInRecord2 {
ListInRecord2 {
a: "list_in_record2".to_string(),
}
}
fn list_in_record3(a: ListInRecord3) -> ListInRecord3 {
assert_eq!(a.a, "list_in_record3 input");
ListInRecord3 {
a: "list_in_record3 output".to_string(),
}
}
fn list_in_record4(a: ListInAlias) -> ListInAlias {
assert_eq!(a.a, "input4");
ListInRecord4 {
a: "result4".to_string(),
}
}
fn list_in_variant1(a: ListInVariant1V1, b: ListInVariant1V2, c: ListInVariant1V3) {
assert_eq!(a.unwrap(), "foo");
assert_eq!(b.unwrap_err(), "bar");
match c {
ListInVariant1V3::String(s) => assert_eq!(s, "baz"),
ListInVariant1V3::F32(_) => panic!(),
}
}
fn list_in_variant2() -> Option<String> {
Some("list_in_variant2".to_string())
}
fn list_in_variant3(a: ListInVariant3) -> Option<String> {
assert_eq!(a.unwrap(), "input3");
Some("output3".to_string())
}
fn errno_result() -> Result<(), MyErrno> {
MyErrno::A.to_string();
format!("{:?}", MyErrno::A);
fn assert_error<T: std::error::Error>() {}
assert_error::<MyErrno>();
Err(MyErrno::B)
}
fn list_typedefs(a: ListTypedef, b: ListTypedef3) -> (ListTypedef2, ListTypedef3) {
assert_eq!(a, "typedef1");
assert_eq!(b.len(), 1);
assert_eq!(b[0], "typedef2");
(b"typedef3".to_vec(), vec!["typedef4".to_string()])
}
}

View File

@@ -0,0 +1,53 @@
test-imports: func()
resource wasm-state
resource wasm-state2
wasm-state-create: func() -> wasm-state
wasm-state-get-val: func(a: wasm-state) -> u32
wasm-state2-create: func() -> wasm-state2
wasm-state2-saw-close: func() -> bool
two-wasm-states: func(a: wasm-state, b: wasm-state2) -> tuple<wasm-state, wasm-state2>
record wasm-state-param-record { a: wasm-state2 }
wasm-state2-param-record: func(a: wasm-state-param-record)
type wasm-state-param-tuple = tuple<wasm-state2>
wasm-state2-param-tuple: func(a: wasm-state-param-tuple)
type wasm-state-param-option = option<wasm-state2>
wasm-state2-param-option: func(a: wasm-state-param-option)
type wasm-state-param-result = expected<wasm-state2, u32>
wasm-state2-param-result: func(a: wasm-state-param-result)
union wasm-state-param-variant { wasm-state2, u32 }
wasm-state2-param-variant: func(a: wasm-state-param-variant)
wasm-state2-param-list: func(a: list<wasm-state2>)
record wasm-state-result-record { a: wasm-state2 }
wasm-state2-result-record: func() -> wasm-state-result-record
type wasm-state-result-tuple = tuple<wasm-state2>
wasm-state2-result-tuple: func() -> wasm-state-result-tuple
type wasm-state-result-option = option<wasm-state2>
wasm-state2-result-option: func() -> wasm-state-result-option
type wasm-state-result-result = expected<wasm-state2, u32>
wasm-state2-result-result: func() -> wasm-state-result-result
union wasm-state-result-variant { wasm-state2, u32 }
wasm-state2-result-variant: func() -> wasm-state-result-variant
wasm-state2-result-list: func() -> list<wasm-state2>
resource markdown {
static create: func() -> option<markdown>
append: func(buf: string)
render: func() -> string
}

View File

@@ -0,0 +1,180 @@
from dataclasses import dataclass
from exports.bindings import Exports
from imports.bindings import add_imports_to_linker, Imports
from typing import Tuple, List
import exports.bindings as e
import imports.bindings as i
import sys
import wasmtime
@dataclass
class HostState(i.HostState):
val: int
def __init__(self, val: int) -> None:
self.val = val
HOST_STATE2_CLOSED = False
@dataclass
class HostState2(i.HostState2):
val: int
def __init__(self, val: int) -> None:
self.val = val
def drop(self) -> None:
global HOST_STATE2_CLOSED
HOST_STATE2_CLOSED = True
@dataclass
class Markdown(i.Markdown2):
buf: str = ''
def append(self, data: str) -> None:
self.buf += data
def render(self) -> str:
return self.buf.replace('red', 'green')
class OddName(i.OddName):
def frob_the_odd(self) -> None:
pass
class MyImports:
def host_state_create(self) -> i.HostState:
return HostState(100)
def host_state_get(self, a: i.HostState) -> int:
assert(isinstance(a, HostState))
return a.val
def host_state2_create(self) -> i.HostState2:
return HostState2(101)
def host_state2_saw_close(self) -> bool:
return HOST_STATE2_CLOSED
def two_host_states(self, a: i.HostState, b: i.HostState2) -> Tuple[i.HostState, i.HostState2]:
return (b, a)
def host_state2_param_record(self, a: i.HostStateParamRecord) -> None:
pass
def host_state2_param_tuple(self, a: i.HostStateParamTuple) -> None:
pass
def host_state2_param_option(self, a: i.HostStateParamOption) -> None:
pass
def host_state2_param_result(self, a: i.HostStateParamResult) -> None:
pass
def host_state2_param_variant(self, a: i.HostStateParamVariant) -> None:
pass
def host_state2_param_list(self, a: List[i.HostState2]) -> None:
pass
def host_state2_result_record(self) -> i.HostStateResultRecord:
return i.HostStateResultRecord(HostState(2))
def host_state2_result_tuple(self) -> i.HostStateResultTuple:
return (HostState(2),)
def host_state2_result_option(self) -> i.HostStateResultOption:
return HostState(2)
def host_state2_result_result(self) -> i.HostStateResultResult:
return i.Ok(HostState2(2))
def host_state2_result_variant(self) -> i.HostStateResultVariant:
return HostState2(2)
def host_state2_result_list(self) -> List[i.HostState2]:
return [HostState2(2), HostState2(5)]
def markdown2_create(self) -> i.Markdown2:
return Markdown()
def odd_name_create(self) -> i.OddName:
return OddName()
def run(wasm_file: str) -> None:
store = wasmtime.Store()
module = wasmtime.Module.from_file(store.engine, wasm_file)
linker = wasmtime.Linker(store.engine)
linker.define_wasi()
wasi = wasmtime.WasiConfig()
wasi.inherit_stdout()
wasi.inherit_stderr()
store.set_wasi(wasi)
imports = MyImports()
add_imports_to_linker(linker, store, imports)
wasm = Exports(store, linker, module)
wasm.test_imports(store)
# Param/result of a handle works in a simple fashion
s: e.WasmState = wasm.wasm_state_create(store)
assert(wasm.wasm_state_get_val(store, s) == 100)
# Deterministic destruction is possible
assert(wasm.wasm_state2_saw_close(store) == False)
s2: e.WasmState2 = wasm.wasm_state2_create(store)
assert(wasm.wasm_state2_saw_close(store) == False)
s2.drop(store)
assert(wasm.wasm_state2_saw_close(store) == True)
arg1 = wasm.wasm_state_create(store)
arg2 = wasm.wasm_state2_create(store)
c, d = wasm.two_wasm_states(store, arg1, arg2)
arg1.drop(store)
arg2.drop(store)
wasm.wasm_state2_param_record(store, e.WasmStateParamRecord(d))
wasm.wasm_state2_param_tuple(store, (d,))
wasm.wasm_state2_param_option(store, d)
wasm.wasm_state2_param_option(store, None)
wasm.wasm_state2_param_result(store, e.Ok(d))
wasm.wasm_state2_param_result(store, e.Err(2))
wasm.wasm_state2_param_variant(store, d)
wasm.wasm_state2_param_variant(store, 2)
wasm.wasm_state2_param_list(store, [])
wasm.wasm_state2_param_list(store, [d])
wasm.wasm_state2_param_list(store, [d, d])
c.drop(store)
d.drop(store)
wasm.wasm_state2_result_record(store).a.drop(store)
wasm.wasm_state2_result_tuple(store)[0].drop(store)
opt = wasm.wasm_state2_result_option(store)
assert(opt is not None)
opt.drop(store)
result = wasm.wasm_state2_result_result(store)
assert(isinstance(result, e.Ok))
result.value.drop(store)
variant = wasm.wasm_state2_result_variant(store)
print(variant)
assert(isinstance(variant, e.WasmState2))
variant.drop(store)
for val in wasm.wasm_state2_result_list(store):
val.drop(store)
s.drop(store)
md = e.Markdown.create(store, wasm)
if md:
md.append(store, "red is the best color")
assert(md.render(store) == "green is the best color")
md.drop(store)
if __name__ == '__main__':
run(sys.argv[1])

View File

@@ -0,0 +1,156 @@
wit_bindgen_wasmtime::export!("../../tests/runtime/handles/imports.wit");
use anyhow::Result;
use imports::*;
use std::cell::RefCell;
#[derive(Default)]
pub struct MyImports {
host_state2_closed: bool,
}
#[derive(Debug)]
pub struct SuchState(u32);
#[derive(Default, Debug)]
pub struct Markdown {
buf: RefCell<String>,
}
impl Imports for MyImports {
type HostState = SuchState;
type HostState2 = ();
type Markdown2 = Markdown;
type OddName = ();
fn host_state_create(&mut self) -> SuchState {
SuchState(100)
}
fn host_state_get(&mut self, state: &SuchState) -> u32 {
state.0
}
fn host_state2_create(&mut self) {}
fn host_state2_saw_close(&mut self) -> bool {
self.host_state2_closed
}
fn drop_host_state2(&mut self, _state: ()) {
self.host_state2_closed = true;
}
fn two_host_states(&mut self, _a: &SuchState, _b: &()) -> (SuchState, ()) {
(SuchState(2), ())
}
fn host_state2_param_record(&mut self, _a: HostStateParamRecord<'_, Self>) {}
fn host_state2_param_tuple(&mut self, _a: (&'_ (),)) {}
fn host_state2_param_option(&mut self, _a: Option<&'_ ()>) {}
fn host_state2_param_result(&mut self, _a: Result<&'_ (), u32>) {}
fn host_state2_param_variant(&mut self, _a: HostStateParamVariant<'_, Self>) {}
fn host_state2_param_list(&mut self, _a: Vec<&()>) {}
fn host_state2_result_record(&mut self) -> HostStateResultRecord<Self> {
HostStateResultRecord { a: () }
}
fn host_state2_result_tuple(&mut self) -> ((),) {
((),)
}
fn host_state2_result_option(&mut self) -> Option<()> {
Some(())
}
fn host_state2_result_result(&mut self) -> Result<(), u32> {
Ok(())
}
fn host_state2_result_variant(&mut self) -> HostStateResultVariant<Self> {
HostStateResultVariant::HostState2(())
}
fn host_state2_result_list(&mut self) -> Vec<()> {
vec![(), ()]
}
fn markdown2_create(&mut self) -> Markdown {
Markdown::default()
}
fn markdown2_append(&mut self, md: &Markdown, buf: &str) {
md.buf.borrow_mut().push_str(buf);
}
fn markdown2_render(&mut self, md: &Markdown) -> String {
md.buf.borrow().replace("red", "green")
}
fn odd_name_create(&mut self) {}
fn odd_name_frob_the_odd(&mut self, _: &()) {}
}
wit_bindgen_wasmtime::import!("../../tests/runtime/handles/exports.wit");
fn run(wasm: &str) -> Result<()> {
use exports::*;
let (exports, mut store) = crate::instantiate(
wasm,
|linker| {
imports::add_to_linker(
linker,
|cx: &mut crate::Context<(MyImports, imports::ImportsTables<MyImports>), _>| {
(&mut cx.imports.0, &mut cx.imports.1)
},
)
},
|store, module, linker| Exports::instantiate(store, module, linker, |cx| &mut cx.exports),
)?;
exports.test_imports(&mut store)?;
let s: WasmState = exports.wasm_state_create(&mut store)?;
assert_eq!(exports.wasm_state_get_val(&mut store, &s)?, 100);
exports.drop_wasm_state(&mut store, s)?;
assert_eq!(exports.wasm_state2_saw_close(&mut store)?, false);
let s: WasmState2 = exports.wasm_state2_create(&mut store)?;
assert_eq!(exports.wasm_state2_saw_close(&mut store)?, false);
exports.drop_wasm_state2(&mut store, s)?;
assert_eq!(exports.wasm_state2_saw_close(&mut store)?, true);
let a = exports.wasm_state_create(&mut store)?;
let b = exports.wasm_state2_create(&mut store)?;
let (s1, s2) = exports.two_wasm_states(&mut store, &a, &b)?;
exports.drop_wasm_state(&mut store, a)?;
exports.drop_wasm_state(&mut store, s1)?;
exports.drop_wasm_state2(&mut store, b)?;
exports.wasm_state2_param_record(&mut store, WasmStateParamRecord { a: &s2 })?;
exports.wasm_state2_param_tuple(&mut store, (&s2,))?;
exports.wasm_state2_param_option(&mut store, Some(&s2))?;
exports.wasm_state2_param_option(&mut store, None)?;
exports.wasm_state2_param_result(&mut store, Ok(&s2))?;
exports.wasm_state2_param_result(&mut store, Err(2))?;
exports.wasm_state2_param_variant(&mut store, WasmStateParamVariant::WasmState2(&s2))?;
exports.wasm_state2_param_variant(&mut store, WasmStateParamVariant::U32(2))?;
exports.wasm_state2_param_list(&mut store, &[])?;
exports.wasm_state2_param_list(&mut store, &[&s2])?;
exports.wasm_state2_param_list(&mut store, &[&s2, &s2])?;
exports.drop_wasm_state2(&mut store, s2)?;
let s = exports.wasm_state2_result_record(&mut store)?.a;
exports.drop_wasm_state2(&mut store, s)?;
let s = exports.wasm_state2_result_tuple(&mut store)?.0;
exports.drop_wasm_state2(&mut store, s)?;
let s = exports.wasm_state2_result_option(&mut store)?.unwrap();
exports.drop_wasm_state2(&mut store, s)?;
let s = exports.wasm_state2_result_result(&mut store)?.unwrap();
match exports.wasm_state2_result_variant(&mut store)? {
WasmStateResultVariant::WasmState2(s) => exports.drop_wasm_state2(&mut store, s)?,
WasmStateResultVariant::U32(_) => panic!(),
}
exports.drop_wasm_state2(&mut store, s)?;
for s in exports.wasm_state2_result_list(&mut store)? {
exports.drop_wasm_state2(&mut store, s)?;
}
Ok(())
}

View File

@@ -0,0 +1,127 @@
import { addImportsToImports, Imports } from "./imports.js";
import { Exports } from "./exports.js";
import * as exports from "./exports.js";
import { getWasm, addWasiToImports } from "./helpers.js";
// @ts-ignore
import * as assert from 'assert';
async function run() {
const importObj = {};
let sawClose = false;
const imports: Imports = {
hostStateCreate() { return 100; },
hostStateGet(x) { return x as number; },
hostState2Create() { return 101; },
hostState2SawClose() { return sawClose; },
dropHostState2(state) { sawClose = true; },
twoHostStates(a, b) { return [b, a]; },
hostState2ParamRecord(x) {},
hostState2ParamTuple(x) {},
hostState2ParamOption(x) {},
hostState2ParamResult(x) {},
hostState2ParamVariant(x) {},
hostState2ParamList(x) {},
hostState2ResultRecord() { return { a: {} }; },
hostState2ResultTuple() { return [{}]; },
hostState2ResultOption() { return 102; },
hostState2ResultResult() { return { tag: 'ok', val: {} }; },
hostState2ResultVariant() { return { tag: 0, val: {} }; },
hostState2ResultList() { return [{}, 3]; },
markdown2Create() {
class Markdown {
buf: string;
constructor() {
this.buf = '';
}
append(extra: string) {
this.buf += extra;
}
render() {
return this.buf.replace('red', 'green');
}
}
return new Markdown();
},
oddNameCreate() {
class OddName {
frobTheOdd() {}
}
return new OddName();
}
};
let instance: WebAssembly.Instance;
addImportsToImports(importObj, imports, name => instance.exports[name]);
const wasi = addWasiToImports(importObj);
const wasm = new Exports();
await wasm.instantiate(getWasm(), importObj);
wasi.start(wasm.instance);
instance = wasm.instance;
wasm.testImports();
// Param/result of a handle works in a simple fashion
const s: exports.WasmState = wasm.wasmStateCreate();
assert.strictEqual(wasm.wasmStateGetVal(s), 100);
// Deterministic destruction is possible
assert.strictEqual(wasm.wasmState2SawClose(), false);
const s2: exports.WasmState2 = wasm.wasmState2Create();
assert.strictEqual(wasm.wasmState2SawClose(), false);
s2.drop();
assert.strictEqual(wasm.wasmState2SawClose(), true);
const arg1 = wasm.wasmStateCreate();
const arg2 = wasm.wasmState2Create();
const [c, d] = wasm.twoWasmStates(arg1, arg2);
arg1.drop();
arg2.drop();
wasm.wasmState2ParamRecord({ a: d });
wasm.wasmState2ParamTuple([d]);
wasm.wasmState2ParamOption(d);
wasm.wasmState2ParamOption(null);
wasm.wasmState2ParamResult({ tag: 'ok', val: d });
wasm.wasmState2ParamResult({ tag: 'err', val: 2 });
wasm.wasmState2ParamVariant({ tag: 0, val: d });
wasm.wasmState2ParamVariant({ tag: 1, val: 2 });
wasm.wasmState2ParamList([]);
wasm.wasmState2ParamList([d]);
wasm.wasmState2ParamList([d, d]);
c.drop();
d.drop();
wasm.wasmState2ResultRecord().a?.drop();
wasm.wasmState2ResultTuple()[0].drop();
const opt = wasm.wasmState2ResultOption();
if (opt === null)
throw new Error('should be some');
opt.drop();
const result = wasm.wasmState2ResultResult();
if (result.tag === 'err')
throw new Error('should be ok');
result.val.drop();
const variant = wasm.wasmState2ResultVariant();
if (variant.tag === 1)
throw new Error('should be 0');
variant.val.drop();
for (let val of wasm.wasmState2ResultList())
val.drop();
s.drop();
const md = exports.Markdown.create(wasm);
if (md) {
md.append("red is the best color");
assert.strictEqual(md.render(), "green is the best color");
md.drop();
}
}
await run()

View File

@@ -0,0 +1,55 @@
resource host-state
resource host-state2
host-state-create: func() -> host-state
host-state-get: func(a: host-state) -> u32
host-state2-create: func() -> host-state2
host-state2-saw-close: func() -> bool
two-host-states: func(a: host-state, b: host-state2) -> tuple<host-state, host-state2>
record host-state-param-record { a: host-state2 }
host-state2-param-record: func(a: host-state-param-record)
type host-state-param-tuple = tuple<host-state2>
host-state2-param-tuple: func(a: host-state-param-tuple)
type host-state-param-option = option<host-state2>
host-state2-param-option: func(a: host-state-param-option)
type host-state-param-result = expected<host-state2, u32>
host-state2-param-result: func(a: host-state-param-result)
union host-state-param-variant { host-state2, u32 }
host-state2-param-variant: func(a: host-state-param-variant)
host-state2-param-list: func(a: list<host-state2>)
record host-state-result-record { a: host-state2 }
host-state2-result-record: func() -> host-state-result-record
type host-state-result-tuple = tuple<host-state2>
host-state2-result-tuple: func() -> host-state-result-tuple
type host-state-result-option = option<host-state2>
host-state2-result-option: func() -> host-state-result-option
type host-state-result-result = expected<host-state2, u32>
host-state2-result-result: func() -> host-state-result-result
union host-state-result-variant { host-state2, u32 }
host-state2-result-variant: func() -> host-state-result-variant
host-state2-result-list: func() -> list<host-state2>
resource markdown2 {
static create: func() -> markdown2
append: func(buf: string)
render: func() -> string
}
resource %odd-name {
static create: func() -> %odd-name
%frob-the-odd: func()
}

View File

@@ -0,0 +1,223 @@
#include <assert.h>
#include <exports.h>
#include <imports.h>
#include <stdlib.h>
#include <string.h>
void exports_test_imports() {
imports_host_state_t s = imports_host_state_create();
assert(imports_host_state_get(s) == 100);
imports_host_state_free(&s);
assert(imports_host_state2_saw_close() == false);
imports_host_state2_t s2 = imports_host_state2_create();
assert(imports_host_state2_saw_close() == false);
imports_host_state2_free(&s2);
assert(imports_host_state2_saw_close() == true);
{
imports_host_state_t a, b;
imports_host_state2_t c, d;
a = imports_host_state_create();
c = imports_host_state2_create();
imports_two_host_states(a, c, &b, &d);
imports_host_state_free(&a);
imports_host_state_free(&b);
imports_host_state2_free(&c);
{
imports_host_state_param_record_t a;
a.a = d;
imports_host_state2_param_record(&a);
}
{
imports_host_state_param_tuple_t a;
a.f0 = d;
imports_host_state2_param_tuple(&a);
}
{
imports_host_state_param_option_t a;
a.is_some = true;
a.val = d;
imports_host_state2_param_option(&a);
}
{
imports_host_state_param_result_t a;
a.is_err = false;
a.val.ok = d;
imports_host_state2_param_result(&a);
a.is_err = true;
a.val.err = 2;
imports_host_state2_param_result(&a);
}
{
imports_host_state_param_variant_t a;
a.tag = 0;
a.val.f0 = d;
imports_host_state2_param_variant(&a);
a.tag = 1;
a.val.f1 = 2;
imports_host_state2_param_variant(&a);
}
{
imports_host_state2_t arr[2];
arr[0] = d;
arr[1] = d;
imports_list_host_state2_t list;
list.len = 0;
list.ptr = arr;
imports_host_state2_param_list(&list);
list.len = 1;
imports_host_state2_param_list(&list);
list.len = 2;
imports_host_state2_param_list(&list);
}
imports_host_state2_free(&d);
}
{
imports_host_state_result_record_t a;
imports_host_state2_result_record(&a);
imports_host_state2_free(&a.a);
}
{
imports_host_state2_t a;
imports_host_state2_result_tuple(&a);
imports_host_state2_free(&a);
}
{
imports_host_state2_t a;
assert(imports_host_state2_result_option(&a));
imports_host_state2_free(&a);
}
{
imports_host_state_result_result_t a;
imports_host_state2_result_result(&a);
assert(!a.is_err);
imports_host_state2_free(&a.val.ok);
}
{
imports_host_state_result_variant_t a;
imports_host_state2_result_variant(&a);
assert(a.tag == 0);
imports_host_state2_free(&a.val.f0);
}
{
imports_list_host_state2_t a;
imports_host_state2_result_list(&a);
imports_list_host_state2_free(&a);
}
{
imports_markdown2_t a = imports_markdown2_create();
imports_string_t s;
imports_string_set(&s, "red is the best color");
imports_markdown2_append(a, &s);
imports_markdown2_render(a, &s);
const char *expected = "green is the best color";
assert(s.len == strlen(expected));
assert(memcmp(s.ptr, expected, s.len) == 0);
imports_string_free(&s);
imports_markdown2_free(&a);
}
}
exports_wasm_state_t exports_wasm_state_create(void) {
return exports_wasm_state_new((void*) 100);
}
uint32_t exports_wasm_state_get_val(exports_wasm_state_t a) {
uint32_t ret = (uint32_t) exports_wasm_state_get(&a);
exports_wasm_state_free(&a);
return ret;
}
exports_wasm_state2_t exports_wasm_state2_create(void) {
return exports_wasm_state2_new((void*) 33);
}
static bool WASM_STATE2_CLOSED = false;
bool exports_wasm_state2_saw_close(void) {
return WASM_STATE2_CLOSED;
}
void exports_wasm_state2_dtor(void *data) {
WASM_STATE2_CLOSED = true;
}
void exports_two_wasm_states(exports_wasm_state_t a, exports_wasm_state2_t b, exports_wasm_state_t *ret0, exports_wasm_state2_t *ret1) {
exports_wasm_state_free(&a);
exports_wasm_state2_free(&b);
*ret0 = exports_wasm_state_new((void*) 101);
*ret1 = exports_wasm_state2_new((void*) 102);
}
void exports_wasm_state2_param_record(exports_wasm_state_param_record_t *a) {
exports_wasm_state_param_record_free(a);
}
void exports_wasm_state2_param_tuple(exports_wasm_state_param_tuple_t *a) {
exports_wasm_state_param_tuple_free(a);
}
void exports_wasm_state2_param_option(exports_wasm_state_param_option_t *a) {
exports_wasm_state_param_option_free(a);
}
void exports_wasm_state2_param_result(exports_wasm_state_param_result_t *a) {
exports_wasm_state_param_result_free(a);
}
void exports_wasm_state2_param_variant(exports_wasm_state_param_variant_t *a) {
exports_wasm_state_param_variant_free(a);
}
void exports_wasm_state2_param_list(exports_list_wasm_state2_t *a) {
exports_list_wasm_state2_free(a);
}
void exports_wasm_state2_result_record(exports_wasm_state_result_record_t *ret0) {
ret0->a = exports_wasm_state2_new((void*) 222);
}
void exports_wasm_state2_result_tuple(exports_wasm_state2_t *ret0) {
*ret0 = exports_wasm_state2_new((void*) 333);
}
bool exports_wasm_state2_result_option(exports_wasm_state2_t *ret0) {
*ret0 = exports_wasm_state2_new((void*) 444);
return true;
}
void exports_wasm_state2_result_result(exports_wasm_state_result_result_t *ret0) {
ret0->is_err = false;
ret0->val.ok = exports_wasm_state2_new((void*) 555);
}
void exports_wasm_state2_result_variant(exports_wasm_state_result_variant_t *ret0) {
ret0->tag = 0;
ret0->val.f0 = exports_wasm_state2_new((void*) 666);
}
void exports_wasm_state2_result_list(exports_list_wasm_state2_t *ret0) {
ret0->len = 2;
ret0->ptr = malloc(2 * sizeof(exports_wasm_state2_t));
ret0->ptr[0] = exports_wasm_state2_new((void*) 777);
ret0->ptr[1] = exports_wasm_state2_new((void*) 888);
}
bool exports_markdown_create(exports_markdown_t *md) {
return false;
}
void exports_markdown_append(exports_markdown_t md, exports_string_t *s) {
abort();
}
void exports_markdown_render(exports_markdown_t md, exports_string_t *ret) {
abort();
}

View File

@@ -0,0 +1,131 @@
wit_bindgen_rust::import!("../../tests/runtime/handles/imports.wit");
wit_bindgen_rust::export!("../../tests/runtime/handles/exports.wit");
use exports::*;
use std::cell::RefCell;
use std::sync::atomic::{AtomicU32, Ordering::SeqCst};
use wit_bindgen_rust::Handle;
struct Exports;
static CLOSED: AtomicU32 = AtomicU32::new(0);
pub struct WasmState(u32);
pub struct WasmState2(u32);
impl exports::Exports for Exports {
fn test_imports() {
use imports::*;
let s: HostState = host_state_create();
assert_eq!(host_state_get(&s), 100);
assert_eq!(host_state2_saw_close(), false);
let s: HostState2 = host_state2_create();
assert_eq!(host_state2_saw_close(), false);
drop(s);
assert_eq!(host_state2_saw_close(), true);
let (_a, s2) = two_host_states(&host_state_create(), &host_state2_create());
host_state2_param_record(HostStateParamRecord { a: &s2 });
host_state2_param_tuple((&s2,));
host_state2_param_option(Some(&s2));
host_state2_param_option(None);
host_state2_param_result(Ok(&s2));
host_state2_param_result(Err(2));
host_state2_param_variant(HostStateParamVariant::HostState2(&s2));
host_state2_param_variant(HostStateParamVariant::U32(2));
host_state2_param_list(&[]);
host_state2_param_list(&[&s2]);
host_state2_param_list(&[&s2, &s2]);
drop(host_state2_result_record().a);
drop(host_state2_result_tuple().0);
drop(host_state2_result_option().unwrap());
drop(host_state2_result_result().unwrap());
drop(host_state2_result_variant());
drop(host_state2_result_list());
let md = Markdown2::create();
md.append("red is the best color");
assert_eq!(md.render(), "green is the best color");
let odd = OddName::create();
odd.frob_the_odd();
}
fn wasm_state_create() -> Handle<WasmState> {
WasmState(100).into()
}
fn wasm_state_get_val(state: Handle<WasmState>) -> u32 {
state.0
}
fn wasm_state2_create() -> Handle<WasmState2> {
WasmState2(33).into()
}
fn wasm_state2_saw_close() -> bool {
CLOSED.load(SeqCst) != 0
}
fn drop_wasm_state2(_state: WasmState2) {
CLOSED.store(1, SeqCst);
}
fn two_wasm_states(
_a: Handle<WasmState>,
_b: Handle<WasmState2>,
) -> (Handle<WasmState>, Handle<WasmState2>) {
(WasmState(101).into(), WasmState2(102).into())
}
fn wasm_state2_param_record(_a: WasmStateParamRecord) {}
fn wasm_state2_param_tuple(_a: (Handle<WasmState2>,)) {}
fn wasm_state2_param_option(_a: Option<Handle<WasmState2>>) {}
fn wasm_state2_param_result(_a: Result<Handle<WasmState2>, u32>) {}
fn wasm_state2_param_variant(_a: WasmStateParamVariant) {}
fn wasm_state2_param_list(_a: Vec<Handle<WasmState2>>) {}
fn wasm_state2_result_record() -> WasmStateResultRecord {
WasmStateResultRecord {
a: WasmState2(222).into(),
}
}
fn wasm_state2_result_tuple() -> (Handle<WasmState2>,) {
(WasmState2(333).into(),)
}
fn wasm_state2_result_option() -> Option<Handle<WasmState2>> {
Some(WasmState2(444).into())
}
fn wasm_state2_result_result() -> Result<Handle<WasmState2>, u32> {
Ok(WasmState2(555).into())
}
fn wasm_state2_result_variant() -> WasmStateResultVariant {
WasmStateResultVariant::WasmState2(Handle::new(WasmState2(666)))
}
fn wasm_state2_result_list() -> Vec<Handle<WasmState2>> {
vec![WasmState2(777).into(), WasmState2(888).into()]
}
}
#[derive(Default)]
pub struct Markdown {
buf: RefCell<String>,
}
impl exports::Markdown for Markdown {
fn create() -> Option<Handle<Markdown>> {
Some(Markdown::default().into())
}
fn append(&self, input: String) {
self.buf.borrow_mut().push_str(&input);
}
fn render(&self) -> String {
self.buf.borrow().replace("red", "green")
}
}

View File

@@ -0,0 +1,9 @@
invalid-u8: func()
invalid-s8: func()
invalid-u16: func()
invalid-s16: func()
invalid-char: func()
invalid-bool: func()
invalid-enum: func()
invalid-handle: func()
invalid-handle-close: func()

View File

@@ -0,0 +1,74 @@
from exports.bindings import Exports
from imports.bindings import add_imports_to_linker, Imports
from typing import Callable
import imports.bindings as i
import sys
import wasmtime
class MyImports(Imports):
def roundtrip_u8(self, x: int) -> int:
raise Exception('unreachable')
def roundtrip_s8(self, x: int) -> int:
raise Exception('unreachable')
def roundtrip_u16(self, x: int) -> int:
raise Exception('unreachable')
def roundtrip_s16(self, x: int) -> int:
raise Exception('unreachable')
def roundtrip_bool(self, x: bool) -> bool:
raise Exception('unreachable')
def roundtrip_char(self, x: str) -> str:
raise Exception('unreachable')
def roundtrip_enum(self, x: i.E) -> i.E:
raise Exception('unreachable')
def get_internal(self, x: i.HostState) -> int:
raise Exception('unreachable')
def run(wasm_file: str) -> None:
store = wasmtime.Store()
module = wasmtime.Module.from_file(store.engine, wasm_file)
linker = wasmtime.Linker(store.engine)
linker.define_wasi()
wasi = wasmtime.WasiConfig()
wasi.inherit_stdout()
wasi.inherit_stderr()
store.set_wasi(wasi)
imports = MyImports()
add_imports_to_linker(linker, store, imports)
wasm = Exports(store, linker, module)
def assert_throws(f: Callable, msg: str) -> None:
try:
f()
raise RuntimeError('expected exception')
except TypeError as e:
actual = str(e)
except OverflowError as e:
actual = str(e)
except ValueError as e:
actual = str(e)
except IndexError as e:
actual = str(e)
if not msg in actual:
print(actual)
assert(msg in actual)
assert_throws(lambda: wasm.invalid_bool(store), 'invalid variant discriminant for bool')
assert_throws(lambda: wasm.invalid_u8(store), 'must be between')
assert_throws(lambda: wasm.invalid_s8(store), 'must be between')
assert_throws(lambda: wasm.invalid_u16(store), 'must be between')
assert_throws(lambda: wasm.invalid_s16(store), 'must be between')
assert_throws(lambda: wasm.invalid_char(store), 'not a valid char')
assert_throws(lambda: wasm.invalid_enum(store), 'not a valid E')
assert_throws(lambda: wasm.invalid_handle(store), 'handle index not valid')
assert_throws(lambda: wasm.invalid_handle_close(store), 'handle index not valid')
if __name__ == '__main__':
run(sys.argv[1])

View File

@@ -0,0 +1,99 @@
wit_bindgen_wasmtime::export!("../../tests/runtime/invalid/imports.wit");
use anyhow::Result;
use imports::*;
use wasmtime::Trap;
#[derive(Default)]
pub struct MyImports;
impl Imports for MyImports {
type HostState = ();
fn roundtrip_u8(&mut self, _: u8) -> u8 {
unreachable!()
}
fn roundtrip_s8(&mut self, _: i8) -> i8 {
unreachable!()
}
fn roundtrip_u16(&mut self, _: u16) -> u16 {
unreachable!()
}
fn roundtrip_s16(&mut self, _: i16) -> i16 {
unreachable!()
}
fn roundtrip_char(&mut self, _: char) -> char {
unreachable!()
}
fn roundtrip_bool(&mut self, _: bool) -> bool {
unreachable!()
}
fn roundtrip_enum(&mut self, _: imports::E) -> imports::E {
unreachable!()
}
fn get_internal(&mut self, _: &()) -> u32 {
unreachable!()
}
}
wit_bindgen_wasmtime::import!("../../tests/runtime/invalid/exports.wit");
fn run(wasm: &str) -> Result<()> {
use exports::*;
let (exports, mut store) = crate::instantiate(
wasm,
|linker| {
imports::add_to_linker(
linker,
|cx: &mut crate::Context<(MyImports, imports::ImportsTables<MyImports>), _>| {
(&mut cx.imports.0, &mut cx.imports.1)
},
)
},
|store, module, linker| Exports::instantiate(store, module, linker, |cx| &mut cx.exports),
)?;
assert_err(
exports.invalid_bool(&mut store),
"invalid discriminant for `bool`",
)?;
assert_err(
exports.invalid_u8(&mut store),
"out-of-bounds integer conversion",
)?;
assert_err(
exports.invalid_s8(&mut store),
"out-of-bounds integer conversion",
)?;
assert_err(
exports.invalid_u16(&mut store),
"out-of-bounds integer conversion",
)?;
assert_err(
exports.invalid_s16(&mut store),
"out-of-bounds integer conversion",
)?;
assert_err(
exports.invalid_char(&mut store),
"char value out of valid range",
)?;
assert_err(
exports.invalid_enum(&mut store),
"invalid discriminant for `E`",
)?;
assert_err(exports.invalid_handle(&mut store), "invalid handle index")?;
assert_err(
exports.invalid_handle_close(&mut store),
"invalid handle index",
)?;
return Ok(());
fn assert_err(result: Result<(), Trap>, err: &str) -> Result<()> {
match result {
Ok(()) => anyhow::bail!("export didn't trap"),
Err(e) if e.to_string().contains(err) => Ok(()),
Err(e) => Err(e.into()),
}
}
}

View File

@@ -0,0 +1,39 @@
import { addImportsToImports, Imports } from "./imports.js";
import { Exports } from "./exports.js";
import { getWasm, addWasiToImports } from "./helpers.js";
// @ts-ignore
import * as assert from 'assert';
async function run() {
const importObj = {};
const imports: Imports = {
roundtripU8(x) { throw new Error('unreachable'); },
roundtripS8(x) { throw new Error('unreachable'); },
roundtripU16(x) { throw new Error('unreachable'); },
roundtripS16(x) { throw new Error('unreachable'); },
roundtripBool(x) { throw new Error('unreachable'); },
roundtripChar(x) { throw new Error('unreachable'); },
roundtripEnum(x) { throw new Error('unreachable'); },
getInternal(x) { throw new Error('unreachable'); },
};
let instance: WebAssembly.Instance;
addImportsToImports(importObj, imports);
const wasi = addWasiToImports(importObj);
const wasm = new Exports();
await wasm.instantiate(getWasm(), importObj);
wasi.start(wasm.instance);
instance = wasm.instance;
assert.throws(() => wasm.invalidBool(), /invalid variant discriminant for bool/);
assert.throws(() => wasm.invalidU8(), /must be between/);
assert.throws(() => wasm.invalidS8(), /must be between/);
assert.throws(() => wasm.invalidU16(), /must be between/);
assert.throws(() => wasm.invalidS16(), /must be between/);
assert.throws(() => wasm.invalidChar(), /not a valid char/);
assert.throws(() => wasm.invalidEnum(), /invalid discriminant specified for E/);
assert.throws(() => wasm.invalidHandle(), /handle index not valid/);
assert.throws(() => wasm.invalidHandleClose(), /handle index not valid/);
}
await run()

View File

@@ -0,0 +1,13 @@
roundtrip-u8: func(a: u8) -> u8
roundtrip-s8: func(a: s8) -> s8
roundtrip-u16: func(a: u16) -> u16
roundtrip-s16: func(a: s16) -> s16
roundtrip-char: func(a: char) -> char
enum e { a, b, c }
roundtrip-enum: func(a: e) -> e
roundtrip-bool: func(a: bool) -> bool
resource host-state
get-internal: func(a: host-state) -> u32

View File

@@ -0,0 +1,88 @@
wit_bindgen_rust::export!("../../tests/runtime/invalid/exports.wit");
#[link(wasm_import_module = "imports")]
extern "C" {
#[link_name = "roundtrip-bool"]
fn roundtrip_bool(a: i32) -> i32;
#[link_name = "roundtrip-u16"]
fn roundtrip_u16(a: i32) -> i32;
#[link_name = "roundtrip-u8"]
fn roundtrip_u8(a: i32) -> i32;
#[link_name = "roundtrip-s16"]
fn roundtrip_s16(a: i32) -> i32;
#[link_name = "roundtrip-s8"]
fn roundtrip_s8(a: i32) -> i32;
#[link_name = "roundtrip-char"]
fn roundtrip_char(a: i32) -> i32;
#[link_name = "roundtrip-enum"]
fn roundtrip_enum(a: i32) -> i32;
#[link_name = "get-internal"]
fn get_internal(a: i32) -> i32;
}
#[link(wasm_import_module = "canonical_abi")]
extern "C" {
#[link_name = "resource_drop_host-state"]
fn resource_drop_host_state(a: i32);
}
struct Exports;
impl exports::Exports for Exports {
fn invalid_u8() {
unsafe {
roundtrip_u8(i32::MAX);
}
unreachable!();
}
fn invalid_s8() {
unsafe {
roundtrip_s8(i32::MAX);
}
unreachable!();
}
fn invalid_u16() {
unsafe {
roundtrip_u16(i32::MAX);
}
unreachable!();
}
fn invalid_s16() {
unsafe {
roundtrip_s16(i32::MAX);
}
unreachable!();
}
fn invalid_char() {
unsafe {
roundtrip_char(0xd800);
}
unreachable!();
}
fn invalid_bool() {
unsafe {
roundtrip_bool(2);
}
unreachable!();
}
fn invalid_enum() {
unsafe {
roundtrip_enum(400);
}
unreachable!();
}
fn invalid_handle() {
unsafe {
get_internal(100);
}
unreachable!();
}
fn invalid_handle_close() {
unsafe {
resource_drop_host_state(100);
}
unreachable!();
}
}

View File

@@ -0,0 +1 @@
nop: func()

View File

@@ -0,0 +1,20 @@
import { Exports } from "./exports.js";
import { getWasm } from "./helpers.js";
async function run() {
const importObj = {};
const wasm = new Exports();
await wasm.instantiate(getWasm(), importObj);
// test other methods of creating a wasm wrapper
(new Exports()).instantiate(getWasm().buffer, importObj);
(new Exports()).instantiate(new Uint8Array(getWasm()), importObj);
(new Exports()).instantiate(new WebAssembly.Module(getWasm()), importObj);
{
const obj = new Exports();
obj.addToImports(importObj);
obj.instantiate(new WebAssembly.Instance(new WebAssembly.Module(getWasm()), importObj));
}
}
await run()

View File

@@ -0,0 +1,3 @@
#include <exports.h>
void exports_nop() {}

View File

@@ -0,0 +1,13 @@
test-imports: func()
allocated-bytes: func() -> u32
list-param: func(a: list<u8>)
list-param2: func(a: string)
list-param3: func(a: list<string>)
list-param4: func(a: list<list<string>>)
list-result: func() -> list<u8>
list-result2: func() -> string
list-result3: func() -> list<string>
list-roundtrip: func(a: list<u8>) -> list<u8>
string-roundtrip: func(a: string) -> string

View File

@@ -0,0 +1,109 @@
from exports.bindings import Exports
from imports.bindings import add_imports_to_linker, Imports
from typing import Tuple, List
import exports.bindings as e
import imports.bindings as i
import sys
import wasmtime
class MyImports:
def list_param(self, a: bytes) -> None:
assert(a == b'\x01\x02\x03\x04')
def list_param2(self, a: str) -> None:
assert(a == 'foo')
def list_param3(self, a: List[str]) -> None:
assert(a == ['foo', 'bar', 'baz'])
def list_param4(self, a: List[List[str]]) -> None:
assert(a == [['foo', 'bar'], ['baz']])
def list_result(self) -> bytes:
return b'\x01\x02\x03\x04\x05'
def list_result2(self) -> str:
return 'hello!'
def list_result3(self) -> List[str]:
return ['hello,', 'world!']
def list_roundtrip(self, a: bytes) -> bytes:
return a
def string_roundtrip(self, a: str) -> str:
return a
def unaligned_roundtrip1(self, a: List[int], b: List[int], c: List[int], d: List[i.Flag32], e: List[i.Flag64]) -> None:
assert(a == [1])
assert(b == [2])
assert(c == [3])
assert(d == [i.Flag32.B8])
assert(e == [i.Flag64.B9])
def unaligned_roundtrip2(self, a: List[i.UnalignedRecord], b: List[float], c: List[float], d: List[str], e: List[bytes]) -> None:
assert(a == [i.UnalignedRecord(a=10, b=11)])
assert(b == [100.0])
assert(c == [101.0])
assert(d == ['foo'])
assert(e == [b'\x66'])
def list_minmax8(self, a: bytes, b: List[int]) -> Tuple[bytes, List[int]]:
assert(a == b'\x00\xff')
assert(b == [-(1 << (8 - 1)), (1 << (8 - 1)) - 1])
return (a, b)
def list_minmax16(self, a: List[int], b: List[int]) -> Tuple[List[int], List[int]]:
assert(a == [0, (1 << 16) - 1])
assert(b == [-(1 << (16 - 1)), (1 << (16 - 1)) - 1])
return (a, b)
def list_minmax32(self, a: List[int], b: List[int]) -> Tuple[List[int], List[int]]:
assert(a == [0, (1 << 32) - 1])
assert(b == [-(1 << (32 - 1)), (1 << (32 - 1)) - 1])
return (a, b)
def list_minmax64(self, a: List[int], b: List[int]) -> Tuple[List[int], List[int]]:
assert(a == [0, (1 << 64) - 1])
assert(b == [-(1 << (64 - 1)), (1 << (64 - 1)) - 1])
return (a, b)
def list_minmax_float(self, a: List[float], b: List[float]) -> Tuple[List[float], List[float]]:
assert(a == [-3.4028234663852886e+38, 3.4028234663852886e+38, -float('inf'), float('inf')])
assert(b == [-sys.float_info.max, sys.float_info.max, -float('inf'), float('inf')])
return (a, b)
def run(wasm_file: str) -> None:
store = wasmtime.Store()
module = wasmtime.Module.from_file(store.engine, wasm_file)
linker = wasmtime.Linker(store.engine)
linker.define_wasi()
wasi = wasmtime.WasiConfig()
wasi.inherit_stdout()
wasi.inherit_stderr()
store.set_wasi(wasi)
imports = MyImports()
add_imports_to_linker(linker, store, imports)
wasm = Exports(store, linker, module)
allocated_bytes = wasm.allocated_bytes(store)
wasm.test_imports(store)
wasm.list_param(store, b'\x01\x02\x03\x04')
wasm.list_param2(store, "foo")
wasm.list_param3(store, ["foo", "bar", "baz"])
wasm.list_param4(store, [["foo", "bar"], ["baz"]])
assert(wasm.list_result(store) == b'\x01\x02\x03\x04\x05')
assert(wasm.list_result2(store) == "hello!")
assert(wasm.list_result3(store) == ["hello,", "world!"])
assert(wasm.string_roundtrip(store, "x") == "x")
assert(wasm.string_roundtrip(store, "") == "")
assert(wasm.string_roundtrip(store, "hello ⚑ world") == "hello ⚑ world")
# Ensure that we properly called `free` everywhere in all the glue that we
# needed to.
assert(allocated_bytes == wasm.allocated_bytes(store))
if __name__ == '__main__':
run(sys.argv[1])

View File

@@ -0,0 +1,159 @@
use anyhow::Result;
wit_bindgen_wasmtime::export!("../../tests/runtime/lists/imports.wit");
use imports::*;
use wit_bindgen_wasmtime::Le;
#[derive(Default)]
pub struct MyImports;
impl Imports for MyImports {
fn list_param(&mut self, list: &[u8]) {
assert_eq!(list, [1, 2, 3, 4]);
}
fn list_param2(&mut self, ptr: &str) {
assert_eq!(ptr, "foo");
}
fn list_param3(&mut self, ptr: Vec<&str>) {
assert_eq!(ptr.len(), 3);
assert_eq!(ptr[0], "foo");
assert_eq!(ptr[1], "bar");
assert_eq!(ptr[2], "baz");
}
fn list_param4(&mut self, ptr: Vec<Vec<&str>>) {
assert_eq!(ptr.len(), 2);
assert_eq!(ptr[0][0], "foo");
assert_eq!(ptr[0][1], "bar");
assert_eq!(ptr[1][0], "baz");
}
fn list_result(&mut self) -> Vec<u8> {
vec![1, 2, 3, 4, 5]
}
fn list_result2(&mut self) -> String {
"hello!".to_string()
}
fn list_result3(&mut self) -> Vec<String> {
vec!["hello,".to_string(), "world!".to_string()]
}
fn list_roundtrip(&mut self, list: &[u8]) -> Vec<u8> {
list.to_vec()
}
fn string_roundtrip(&mut self, s: &str) -> String {
s.to_string()
}
fn list_minmax8(&mut self, u: &[u8], s: &[i8]) -> (Vec<u8>, Vec<i8>) {
assert_eq!(u, [u8::MIN, u8::MAX]);
assert_eq!(s, [i8::MIN, i8::MAX]);
(u.to_vec(), s.to_vec())
}
fn list_minmax16(&mut self, u: &[Le<u16>], s: &[Le<i16>]) -> (Vec<u16>, Vec<i16>) {
assert_eq!(u, [u16::MIN, u16::MAX]);
assert_eq!(s, [i16::MIN, i16::MAX]);
(
u.iter().map(|e| e.get()).collect(),
s.iter().map(|e| e.get()).collect(),
)
}
fn list_minmax32(&mut self, u: &[Le<u32>], s: &[Le<i32>]) -> (Vec<u32>, Vec<i32>) {
assert_eq!(u, [u32::MIN, u32::MAX]);
assert_eq!(s, [i32::MIN, i32::MAX]);
(
u.iter().map(|e| e.get()).collect(),
s.iter().map(|e| e.get()).collect(),
)
}
fn list_minmax64(&mut self, u: &[Le<u64>], s: &[Le<i64>]) -> (Vec<u64>, Vec<i64>) {
assert_eq!(u, [u64::MIN, u64::MAX]);
assert_eq!(s, [i64::MIN, i64::MAX]);
(
u.iter().map(|e| e.get()).collect(),
s.iter().map(|e| e.get()).collect(),
)
}
fn list_minmax_float(&mut self, u: &[Le<f32>], s: &[Le<f64>]) -> (Vec<f32>, Vec<f64>) {
assert_eq!(u, [f32::MIN, f32::MAX, f32::NEG_INFINITY, f32::INFINITY]);
assert_eq!(s, [f64::MIN, f64::MAX, f64::NEG_INFINITY, f64::INFINITY]);
(
u.iter().map(|e| e.get()).collect(),
s.iter().map(|e| e.get()).collect(),
)
}
fn unaligned_roundtrip1(
&mut self,
u16s: &[Le<u16>],
u32s: &[Le<u32>],
u64s: &[Le<u64>],
flag32s: Vec<Flag32>,
flag64s: Vec<Flag64>,
) {
assert_eq!(u16s, [1]);
assert_eq!(u32s, [2]);
assert_eq!(u64s, [3]);
assert_eq!(flag32s, [Flag32::B8]);
assert_eq!(flag64s, [Flag64::B9]);
}
fn unaligned_roundtrip2(
&mut self,
records: &[Le<UnalignedRecord>],
f32s: &[Le<f32>],
f64s: &[Le<f64>],
strings: Vec<&str>,
lists: Vec<&[u8]>,
) {
assert_eq!(records.len(), 1);
assert_eq!(records[0].get().a, 10);
assert_eq!(records[0].get().b, 11);
assert_eq!(f32s, [100.0]);
assert_eq!(f64s, [101.0]);
assert_eq!(strings, ["foo"]);
assert_eq!(lists, [&[102][..]]);
}
}
wit_bindgen_wasmtime::import!("../../tests/runtime/lists/exports.wit");
fn run(wasm: &str) -> Result<()> {
use exports::*;
let (exports, mut store) = crate::instantiate(
wasm,
|linker| imports::add_to_linker(linker, |cx| -> &mut MyImports { &mut cx.imports }),
|store, module, linker| Exports::instantiate(store, module, linker, |cx| &mut cx.exports),
)?;
let bytes = exports.allocated_bytes(&mut store)?;
exports.test_imports(&mut store)?;
exports.list_param(&mut store, &[1, 2, 3, 4])?;
exports.list_param2(&mut store, "foo")?;
exports.list_param3(&mut store, &["foo", "bar", "baz"])?;
exports.list_param4(&mut store, &[&["foo", "bar"], &["baz"]])?;
assert_eq!(exports.list_result(&mut store)?, [1, 2, 3, 4, 5]);
assert_eq!(exports.list_result2(&mut store)?, "hello!");
assert_eq!(exports.list_result3(&mut store)?, ["hello,", "world!"]);
assert_eq!(exports.string_roundtrip(&mut store, "x")?, "x");
assert_eq!(exports.string_roundtrip(&mut store, "")?, "");
assert_eq!(
exports.string_roundtrip(&mut store, "hello ⚑ world")?,
"hello ⚑ world"
);
// Ensure that we properly called `free` everywhere in all the glue that we
// needed to.
assert_eq!(bytes, exports.allocated_bytes(&mut store)?);
Ok(())
}

View File

@@ -0,0 +1,139 @@
import { addImportsToImports, Imports, FLAG32_B8, FLAG64_B9 } from "./imports.js";
import { Exports } from "./exports.js";
import * as exports from "./exports.js";
import { getWasm, addWasiToImports } from "./helpers.js";
// @ts-ignore
import * as assert from 'assert';
async function run() {
const importObj = {};
const imports: Imports = {
listParam(a) {
assert.deepStrictEqual(Array.from(a), [1, 2, 3, 4]);
},
listParam2(a) {
assert.strictEqual(a, 'foo');
},
listParam3(a) {
assert.deepStrictEqual(a, ['foo', 'bar', 'baz']);
},
listParam4(a) {
assert.deepStrictEqual(a, [['foo', 'bar'], ['baz']]);
},
listResult() {
return new Uint8Array([1, 2, 3, 4, 5]);
},
listResult2() { return 'hello!'; },
listResult3() { return ['hello,', 'world!']; },
listRoundtrip(x) { return x; },
stringRoundtrip(x) { return x; },
unalignedRoundtrip1(u16, u32, u64, flag32, flag64) {
assert.deepStrictEqual(Array.from(u16), [1]);
assert.deepStrictEqual(Array.from(u32), [2]);
assert.deepStrictEqual(Array.from(u64), [3n]);
assert.deepStrictEqual(flag32, [FLAG32_B8]);
assert.deepStrictEqual(flag64, [FLAG64_B9]);
},
unalignedRoundtrip2(record, f32, f64, string, list) {
assert.deepStrictEqual(Array.from(record), [{ a: 10, b: 11n }]);
assert.deepStrictEqual(Array.from(f32), [100]);
assert.deepStrictEqual(Array.from(f64), [101]);
assert.deepStrictEqual(string, ['foo']);
assert.deepStrictEqual(list, [new Uint8Array([102])]);
},
listMinmax8(u, s) {
assert.deepEqual(u.length, 2);
assert.deepEqual(u[0], 0);
assert.deepEqual(u[1], (1 << 8) - 1);
assert.deepEqual(s.length, 2);
assert.deepEqual(s[0], -(1 << 7));
assert.deepEqual(s[1], (1 << 7) - 1);
return [u, s];
},
listMinmax16(u, s) {
assert.deepEqual(u.length, 2);
assert.deepEqual(u[0], 0);
assert.deepEqual(u[1], (1 << 16) - 1);
assert.deepEqual(s.length, 2);
assert.deepEqual(s[0], -(1 << 15));
assert.deepEqual(s[1], (1 << 15) - 1);
return [u, s];
},
listMinmax32(u, s) {
assert.deepEqual(u.length, 2);
assert.deepEqual(u[0], 0);
assert.deepEqual(u[1], ~0 >>> 0);
assert.deepEqual(s.length, 2);
assert.deepEqual(s[0], 1 << 31);
assert.deepEqual(s[1], ((1 << 31) - 1) >>> 0);
return [u, s];
},
listMinmax64(u, s) {
assert.deepEqual(u.length, 2);
assert.deepEqual(u[0], 0n);
assert.deepEqual(u[1], (2n ** 64n) - 1n);
assert.deepEqual(s.length, 2);
assert.deepEqual(s[0], -(2n ** 63n));
assert.deepEqual(s[1], (2n ** 63n) - 1n);
return [u, s];
},
listMinmaxFloat(f, d) {
assert.deepEqual(f.length, 4);
assert.deepEqual(f[0], -3.4028234663852886e+38);
assert.deepEqual(f[1], 3.4028234663852886e+38);
assert.deepEqual(f[2], Number.NEGATIVE_INFINITY);
assert.deepEqual(f[3], Number.POSITIVE_INFINITY);
assert.deepEqual(d.length, 4);
assert.deepEqual(d[0], -Number.MAX_VALUE);
assert.deepEqual(d[1], Number.MAX_VALUE);
assert.deepEqual(d[2], Number.NEGATIVE_INFINITY);
assert.deepEqual(d[3], Number.POSITIVE_INFINITY);
return [f, d];
},
};
let instance: WebAssembly.Instance;
addImportsToImports(importObj, imports, name => instance.exports[name]);
const wasi = addWasiToImports(importObj);
const wasm = new Exports();
await wasm.instantiate(getWasm(), importObj);
wasi.start(wasm.instance);
instance = wasm.instance;
const bytes = wasm.allocatedBytes();
wasm.testImports();
wasm.listParam(new Uint8Array([1, 2, 3, 4]));
wasm.listParam2("foo");
wasm.listParam3(["foo", "bar", "baz"]);
wasm.listParam4([["foo", "bar"], ["baz"]]);
assert.deepStrictEqual(Array.from(wasm.listResult()), [1, 2, 3, 4, 5]);
assert.deepStrictEqual(wasm.listResult2(), "hello!");
assert.deepStrictEqual(wasm.listResult3(), ["hello,", "world!"]);
const buffer = new ArrayBuffer(8);
(new Uint8Array(buffer)).set(new Uint8Array([1, 2, 3, 4]), 2);
// Create a view of the four bytes in the middle of the buffer
const view = new Uint8Array(buffer, 2, 4);
assert.deepStrictEqual(Array.from(wasm.listRoundtrip(view)), [1, 2, 3, 4]);
assert.deepStrictEqual(wasm.stringRoundtrip("x"), "x");
assert.deepStrictEqual(wasm.stringRoundtrip(""), "");
assert.deepStrictEqual(wasm.stringRoundtrip("hello ⚑ world"), "hello ⚑ world");
// Ensure that we properly called `free` everywhere in all the glue that we
// needed to.
assert.strictEqual(bytes, wasm.allocatedBytes());
}
await run()

View File

@@ -0,0 +1,40 @@
flags flag32 {
b0, b1, b2, b3, b4, b5, b6, b7,
b8, b9, b10, b11, b12, b13, b14, b15,
b16, b17, b18, b19, b20, b21, b22, b23,
b24, b25, b26, b27, b28, b29, b30, b31,
}
flags flag64 {
b0, b1, b2, b3, b4, b5, b6, b7,
b8, b9, b10, b11, b12, b13, b14, b15,
b16, b17, b18, b19, b20, b21, b22, b23,
b24, b25, b26, b27, b28, b29, b30, b31,
b32, b33, b34, b35, b36, b37, b38, b39,
b40, b41, b42, b43, b44, b45, b46, b47,
b48, b49, b50, b51, b52, b53, b54, b55,
b56, b57, b58, b59, b60, b61, b62, b63,
}
list-param: func(a: list<u8>)
list-param2: func(a: string)
list-param3: func(a: list<string>)
list-param4: func(a: list<list<string>>)
list-result: func() -> list<u8>
list-result2: func() -> string
list-result3: func() -> list<string>
list-minmax8: func(a: list<u8>, b: list<s8>) -> tuple<list<u8>, list<s8>>
list-minmax16: func(a: list<u16>, b: list<s16>) -> tuple<list<u16>, list<s16>>
list-minmax32: func(a: list<u32>, b: list<s32>) -> tuple<list<u32>, list<s32>>
list-minmax64: func(a: list<u64>, b: list<s64>) -> tuple<list<u64>, list<s64>>
list-minmax-float: func(a: list<float32>, b: list<float64>) -> tuple<list<float32>, list<float64>>
list-roundtrip: func(a: list<u8>) -> list<u8>
string-roundtrip: func(a: string) -> string
unaligned-roundtrip1: func(a: list<u16>, b: list<u32>, c: list<u64>, d: list<flag32>, e: list<flag64>)
record unaligned-record { a: u32, b: u64 }
unaligned-roundtrip2: func(a: list<unaligned-record>, b: list<float32>, c: list<float64>, d: list<string>, e: list<list<u8>>)

View File

@@ -0,0 +1,292 @@
#include <assert.h>
#include <exports.h>
#include <float.h>
#include <imports.h>
#include <limits.h>
#include <math.h>
#include <stdalign.h>
#include <stdlib.h>
#include <string.h>
// "custom allocator" which just keeps track of allocated bytes
static size_t ALLOCATED_BYTES = 0;
__attribute__((export_name("canonical_abi_realloc")))
void *canonical_abi_realloc( void *ptr, size_t orig_size, size_t orig_align, size_t new_size) {
void *ret = realloc(ptr, new_size);
if (!ret)
abort();
ALLOCATED_BYTES -= orig_size;
ALLOCATED_BYTES += new_size;
return ret;
}
__attribute__((export_name("canonical_abi_free")))
void canonical_abi_free(void *ptr, size_t size, size_t align) {
if (size > 0) {
ALLOCATED_BYTES -= size;
free(ptr);
}
}
uint32_t exports_allocated_bytes(void) {
return ALLOCATED_BYTES;
}
void exports_test_imports() {
{
uint8_t list[] = {1, 2, 3, 4};
imports_list_u8_t a;
a.ptr = list;
a.len = 4;
imports_list_param(&a);
}
{
imports_string_t a;
imports_string_set(&a, "foo");
imports_list_param2(&a);
}
{
imports_string_t list[3];
imports_string_set(&list[0], "foo");
imports_string_set(&list[1], "bar");
imports_string_set(&list[2], "baz");
imports_list_string_t a;
a.ptr = list;
a.len = 3;
imports_list_param3(&a);
}
{
imports_string_t list1[2];
imports_string_t list2[1];
imports_string_set(&list1[0], "foo");
imports_string_set(&list1[1], "bar");
imports_string_set(&list2[0], "baz");
imports_list_list_string_t a;
a.ptr[0].len = 2;
a.ptr[0].ptr = list1;
a.ptr[1].len = 1;
a.ptr[1].ptr = list2;
a.len = 2;
imports_list_param4(&a);
}
{
imports_list_u8_t a;
imports_list_result(&a);
assert(a.len == 5);
assert(memcmp(a.ptr, "\x01\x02\x03\x04\x05", 5) == 0);
imports_list_u8_free(&a);
}
{
imports_string_t a;
imports_list_result2(&a);
assert(a.len == 6);
assert(memcmp(a.ptr, "hello!", 6) == 0);
imports_string_free(&a);
}
{
imports_list_string_t a;
imports_list_result3(&a);
assert(a.len == 2);
assert(a.ptr[0].len == 6);
assert(a.ptr[1].len == 6);
assert(memcmp(a.ptr[0].ptr, "hello,", 6) == 0);
assert(memcmp(a.ptr[1].ptr, "world!", 6) == 0);
imports_list_string_free(&a);
}
{
imports_string_t a, b;
imports_string_set(&a, "x");
imports_string_roundtrip(&a, &b);
assert(b.len == a.len);
assert(memcmp(b.ptr, a.ptr, a.len) == 0);
imports_string_free(&b);
imports_string_set(&a, "");
imports_string_roundtrip(&a, &b);
assert(b.len == a.len);
imports_string_free(&b);
imports_string_set(&a, "hello");
imports_string_roundtrip(&a, &b);
assert(b.len == a.len);
assert(memcmp(b.ptr, a.ptr, a.len) == 0);
imports_string_free(&b);
imports_string_set(&a, "hello ⚑ world");
imports_string_roundtrip(&a, &b);
assert(b.len == a.len);
assert(memcmp(b.ptr, a.ptr, a.len) == 0);
imports_string_free(&b);
}
{
uint8_t u8[2] = {0, UCHAR_MAX};
int8_t s8[2] = {SCHAR_MIN, SCHAR_MAX};
imports_list_u8_t list_u8 = { u8, 2 };
imports_list_s8_t list_s8 = { s8, 2 };
imports_list_u8_t list_u8_out;
imports_list_s8_t list_s8_out;
imports_list_minmax8(&list_u8, &list_s8, &list_u8_out, &list_s8_out);
assert(list_u8_out.len == 2 && list_u8_out.ptr[0] == 0 && list_u8_out.ptr[1] == UCHAR_MAX);
assert(list_s8_out.len == 2 && list_s8_out.ptr[0] == SCHAR_MIN && list_s8_out.ptr[1] == SCHAR_MAX);
imports_list_u8_free(&list_u8_out);
imports_list_s8_free(&list_s8_out);
}
{
uint16_t u16[2] = {0, USHRT_MAX};
int16_t s16[2] = {SHRT_MIN, SHRT_MAX};
imports_list_u16_t list_u16 = { u16, 2 };
imports_list_s16_t list_s16 = { s16, 2 };
imports_list_u16_t list_u16_out;
imports_list_s16_t list_s16_out;
imports_list_minmax16(&list_u16, &list_s16, &list_u16_out, &list_s16_out);
assert(list_u16_out.len == 2 && list_u16_out.ptr[0] == 0 && list_u16_out.ptr[1] == USHRT_MAX);
assert(list_s16_out.len == 2 && list_s16_out.ptr[0] == SHRT_MIN && list_s16_out.ptr[1] == SHRT_MAX);
imports_list_u16_free(&list_u16_out);
imports_list_s16_free(&list_s16_out);
}
{
uint32_t u32[2] = {0, UINT_MAX};
int32_t s32[2] = {INT_MIN, INT_MAX};
imports_list_u32_t list_u32 = { u32, 2 };
imports_list_s32_t list_s32 = { s32, 2 };
imports_list_u32_t list_u32_out;
imports_list_s32_t list_s32_out;
imports_list_minmax32(&list_u32, &list_s32, &list_u32_out, &list_s32_out);
assert(list_u32_out.len == 2 && list_u32_out.ptr[0] == 0 && list_u32_out.ptr[1] == UINT_MAX);
assert(list_s32_out.len == 2 && list_s32_out.ptr[0] == INT_MIN && list_s32_out.ptr[1] == INT_MAX);
imports_list_u32_free(&list_u32_out);
imports_list_s32_free(&list_s32_out);
}
{
uint64_t u64[2] = {0, ULLONG_MAX};
int64_t s64[2] = {LLONG_MIN, LLONG_MAX};
imports_list_u64_t list_u64 = { u64, 2 };
imports_list_s64_t list_s64 = { s64, 2 };
imports_list_u64_t list_u64_out;
imports_list_s64_t list_s64_out;
imports_list_minmax64(&list_u64, &list_s64, &list_u64_out, &list_s64_out);
assert(list_u64_out.len == 2 && list_u64_out.ptr[0] == 0 && list_u64_out.ptr[1] == ULLONG_MAX);
assert(list_s64_out.len == 2 && list_s64_out.ptr[0] == LLONG_MIN && list_s64_out.ptr[1] == LLONG_MAX);
imports_list_u64_free(&list_u64_out);
imports_list_s64_free(&list_s64_out);
}
{
float f32[4] = {-FLT_MAX, FLT_MAX, -INFINITY, INFINITY};
double f64[4] = {-DBL_MAX, DBL_MAX, -INFINITY, INFINITY};
imports_list_float32_t list_float32 = { f32, 4 };
imports_list_float64_t list_float64 = { f64, 4 };
imports_list_float32_t list_float32_out;
imports_list_float64_t list_float64_out;
imports_list_minmax_float(&list_float32, &list_float64, &list_float32_out, &list_float64_out);
assert(list_float32_out.len == 4 && list_float32_out.ptr[0] == -FLT_MAX && list_float32_out.ptr[1] == FLT_MAX);
assert(list_float32_out.ptr[2] == -INFINITY && list_float32_out.ptr[3] == INFINITY);
assert(list_float64_out.len == 4 && list_float64_out.ptr[0] == -DBL_MAX && list_float64_out.ptr[1] == DBL_MAX);
assert(list_float64_out.ptr[2] == -INFINITY && list_float64_out.ptr[3] == INFINITY);
imports_list_float32_free(&list_float32_out);
imports_list_float64_free(&list_float64_out);
}
}
void exports_list_param(exports_list_u8_t *a) {
assert(a->len == 4);
assert(a->ptr[0] == 1);
assert(a->ptr[1] == 2);
assert(a->ptr[2] == 3);
assert(a->ptr[3] == 4);
exports_list_u8_free(a);
}
void exports_list_param2(exports_string_t *a) {
assert(a->len == 3);
assert(a->ptr[0] == 'f');
assert(a->ptr[1] == 'o');
assert(a->ptr[2] == 'o');
exports_string_free(a);
}
void exports_list_param3(exports_list_string_t *a) {
assert(a->len == 3);
assert(a->ptr[0].len == 3);
assert(a->ptr[0].ptr[0] == 'f');
assert(a->ptr[0].ptr[1] == 'o');
assert(a->ptr[0].ptr[2] == 'o');
assert(a->ptr[1].len == 3);
assert(a->ptr[1].ptr[0] == 'b');
assert(a->ptr[1].ptr[1] == 'a');
assert(a->ptr[1].ptr[2] == 'r');
assert(a->ptr[2].len == 3);
assert(a->ptr[2].ptr[0] == 'b');
assert(a->ptr[2].ptr[1] == 'a');
assert(a->ptr[2].ptr[2] == 'z');
exports_list_string_free(a);
}
void exports_list_param4(exports_list_list_string_t *a) {
assert(a->len == 2);
assert(a->ptr[0].len == 2);
assert(a->ptr[1].len == 1);
assert(a->ptr[0].ptr[0].len == 3);
assert(a->ptr[0].ptr[0].ptr[0] == 'f');
assert(a->ptr[0].ptr[0].ptr[1] == 'o');
assert(a->ptr[0].ptr[0].ptr[2] == 'o');
assert(a->ptr[0].ptr[1].len == 3);
assert(a->ptr[0].ptr[1].ptr[0] == 'b');
assert(a->ptr[0].ptr[1].ptr[1] == 'a');
assert(a->ptr[0].ptr[1].ptr[2] == 'r');
assert(a->ptr[1].ptr[0].len == 3);
assert(a->ptr[1].ptr[0].ptr[0] == 'b');
assert(a->ptr[1].ptr[0].ptr[1] == 'a');
assert(a->ptr[1].ptr[0].ptr[2] == 'z');
exports_list_list_string_free(a);
}
void exports_list_result(exports_list_u8_t *ret0) {
ret0->ptr = canonical_abi_realloc(NULL, 0, 1, 5);
ret0->len = 5;
ret0->ptr[0] = 1;
ret0->ptr[1] = 2;
ret0->ptr[2] = 3;
ret0->ptr[3] = 4;
ret0->ptr[4] = 5;
}
void exports_list_result2(exports_string_t *ret0) {
exports_string_dup(ret0, "hello!");
}
void exports_list_result3(exports_list_string_t *ret0) {
ret0->len = 2;
ret0->ptr = canonical_abi_realloc(NULL, 0, alignof(exports_string_t), 2 * sizeof(exports_string_t));
exports_string_dup(&ret0->ptr[0], "hello,");
exports_string_dup(&ret0->ptr[1], "world!");
}
void exports_list_roundtrip(exports_list_u8_t *a, exports_list_u8_t *ret0) {
*ret0 = *a;
}
void exports_string_roundtrip(exports_string_t *a, exports_string_t *ret0) {
*ret0 = *a;
}

View File

@@ -0,0 +1,169 @@
wit_bindgen_rust::import!("../../tests/runtime/lists/imports.wit");
wit_bindgen_rust::export!("../../tests/runtime/lists/exports.wit");
use std::alloc::{self, Layout};
use std::mem;
use std::ptr;
struct Exports;
impl exports::Exports for Exports {
fn allocated_bytes() -> u32 {
test_rust_wasm::get() as u32
}
fn test_imports() {
use imports::*;
let _guard = test_rust_wasm::guard();
list_param(&[1, 2, 3, 4]);
list_param2("foo");
list_param3(&["foo", "bar", "baz"]);
list_param4(&[&["foo", "bar"], &["baz"]]);
assert_eq!(list_result(), [1, 2, 3, 4, 5]);
assert_eq!(list_result2(), "hello!");
assert_eq!(list_result3(), ["hello,", "world!"]);
assert_eq!(string_roundtrip("x"), "x");
assert_eq!(string_roundtrip(""), "");
assert_eq!(string_roundtrip("hello"), "hello");
assert_eq!(string_roundtrip("hello ⚑ world"), "hello ⚑ world");
struct Unaligned<T: Copy> {
alloc: *mut u8,
_marker: std::marker::PhantomData<T>,
}
impl<T: Copy> Unaligned<T> {
fn layout() -> Layout {
Layout::from_size_align(2 * mem::size_of::<T>(), 8).unwrap()
}
fn new(data: T) -> Unaligned<T> {
unsafe {
let alloc = alloc::alloc(Self::layout());
assert!(!alloc.is_null());
ptr::write_unaligned(alloc.add(1).cast(), data);
Unaligned {
alloc,
_marker: Default::default(),
}
}
}
fn as_slice(&self) -> *const [T] {
unsafe { ptr::slice_from_raw_parts(self.alloc.add(1).cast(), 1) }
}
}
impl<T: Copy> Drop for Unaligned<T> {
fn drop(&mut self) {
unsafe {
alloc::dealloc(self.alloc, Self::layout());
}
}
}
unsafe {
let u16s = Unaligned::new(1);
let u32s = Unaligned::new(2);
let u64s = Unaligned::new(3);
let flag32s = Unaligned::new(Flag32::B8);
let flag64s = Unaligned::new(Flag64::B9);
let records = Unaligned::new(UnalignedRecord { a: 10, b: 11 });
let f32s = Unaligned::new(100.0);
let f64s = Unaligned::new(101.0);
let strings = Unaligned::new("foo");
let lists = Unaligned::new(&[102][..]);
// Technically this is UB because we're creating safe slices from
// unaligned pointers, but we're hoping that because we're just passing
// off pointers to an import through a safe import we can get away with
// this. If this ever becomes a problem we'll just need to call the raw
// import with raw integers.
unaligned_roundtrip1(
&*u16s.as_slice(),
&*u32s.as_slice(),
&*u64s.as_slice(),
&*flag32s.as_slice(),
&*flag64s.as_slice(),
);
unaligned_roundtrip2(
&*records.as_slice(),
&*f32s.as_slice(),
&*f64s.as_slice(),
&*strings.as_slice(),
&*lists.as_slice(),
);
}
assert_eq!(
list_minmax8(&[u8::MIN, u8::MAX], &[i8::MIN, i8::MAX]),
(vec![u8::MIN, u8::MAX], vec![i8::MIN, i8::MAX]),
);
assert_eq!(
list_minmax16(&[u16::MIN, u16::MAX], &[i16::MIN, i16::MAX]),
(vec![u16::MIN, u16::MAX], vec![i16::MIN, i16::MAX]),
);
assert_eq!(
list_minmax32(&[u32::MIN, u32::MAX], &[i32::MIN, i32::MAX]),
(vec![u32::MIN, u32::MAX], vec![i32::MIN, i32::MAX]),
);
assert_eq!(
list_minmax64(&[u64::MIN, u64::MAX], &[i64::MIN, i64::MAX]),
(vec![u64::MIN, u64::MAX], vec![i64::MIN, i64::MAX]),
);
assert_eq!(
list_minmax_float(
&[f32::MIN, f32::MAX, f32::NEG_INFINITY, f32::INFINITY],
&[f64::MIN, f64::MAX, f64::NEG_INFINITY, f64::INFINITY]
),
(
vec![f32::MIN, f32::MAX, f32::NEG_INFINITY, f32::INFINITY],
vec![f64::MIN, f64::MAX, f64::NEG_INFINITY, f64::INFINITY],
),
);
}
fn list_param(list: Vec<u8>) {
assert_eq!(list, [1, 2, 3, 4]);
}
fn list_param2(ptr: String) {
assert_eq!(ptr, "foo");
}
fn list_param3(ptr: Vec<String>) {
assert_eq!(ptr.len(), 3);
assert_eq!(ptr[0], "foo");
assert_eq!(ptr[1], "bar");
assert_eq!(ptr[2], "baz");
}
fn list_param4(ptr: Vec<Vec<String>>) {
assert_eq!(ptr.len(), 2);
assert_eq!(ptr[0][0], "foo");
assert_eq!(ptr[0][1], "bar");
assert_eq!(ptr[1][0], "baz");
}
fn list_result() -> Vec<u8> {
vec![1, 2, 3, 4, 5]
}
fn list_result2() -> String {
"hello!".to_string()
}
fn list_result3() -> Vec<String> {
vec!["hello,".to_string(), "world!".to_string()]
}
fn list_roundtrip(x: Vec<u8>) -> Vec<u8> {
x.clone()
}
fn string_roundtrip(x: String) -> String {
x.clone()
}
}

View File

@@ -0,0 +1,22 @@
many-arguments: func(
a1: u64,
a2: u64,
a3: u64,
a4: u64,
a5: u64,
a6: u64,
a7: u64,
a8: u64,
a9: u64,
a10: u64,
a11: u64,
a12: u64,
a13: u64,
a14: u64,
a15: u64,
a16: u64,
a17: u64,
a18: u64,
a19: u64,
a20: u64,
)

View File

@@ -0,0 +1,68 @@
from exports.bindings import Exports
from imports.bindings import add_imports_to_linker, Imports
import math;
import sys
import wasmtime
class MyImports:
def many_arguments(self,
a1: int,
a2: int,
a3: int,
a4: int,
a5: int,
a6: int,
a7: int,
a8: int,
a9: int,
a10: int,
a11: int,
a12: int,
a13: int,
a14: int,
a15: int,
a16: int,
a17: int,
a18: int,
a19: int,
a20: int) -> None:
assert(a1 == 1)
assert(a2 == 2)
assert(a3 == 3)
assert(a4 == 4)
assert(a5 == 5)
assert(a6 == 6)
assert(a7 == 7)
assert(a8 == 8)
assert(a9 == 9)
assert(a10 == 10)
assert(a11 == 11)
assert(a12 == 12)
assert(a13 == 13)
assert(a14 == 14)
assert(a15 == 15)
assert(a16 == 16)
assert(a17 == 17)
assert(a18 == 18)
assert(a19 == 19)
assert(a20 == 20)
def run(wasm_file: str) -> None:
store = wasmtime.Store()
module = wasmtime.Module.from_file(store.engine, wasm_file)
linker = wasmtime.Linker(store.engine)
linker.define_wasi()
wasi = wasmtime.WasiConfig()
wasi.inherit_stdout()
wasi.inherit_stderr()
store.set_wasi(wasi)
imports = MyImports()
add_imports_to_linker(linker, store, imports)
wasm = Exports(store, linker, module)
wasm.many_arguments(store, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,14, 15, 16, 17, 18, 19, 20)
if __name__ == '__main__':
run(sys.argv[1])

View File

@@ -0,0 +1,71 @@
use anyhow::Result;
wit_bindgen_wasmtime::export!("../../tests/runtime/many_arguments/imports.wit");
#[derive(Default)]
pub struct MyImports {}
impl imports::Imports for MyImports {
fn many_arguments(
&mut self,
a1: u64,
a2: u64,
a3: u64,
a4: u64,
a5: u64,
a6: u64,
a7: u64,
a8: u64,
a9: u64,
a10: u64,
a11: u64,
a12: u64,
a13: u64,
a14: u64,
a15: u64,
a16: u64,
a17: u64,
a18: u64,
a19: u64,
a20: u64,
) {
assert_eq!(a1, 1);
assert_eq!(a2, 2);
assert_eq!(a3, 3);
assert_eq!(a4, 4);
assert_eq!(a5, 5);
assert_eq!(a6, 6);
assert_eq!(a7, 7);
assert_eq!(a8, 8);
assert_eq!(a9, 9);
assert_eq!(a10, 10);
assert_eq!(a11, 11);
assert_eq!(a12, 12);
assert_eq!(a13, 13);
assert_eq!(a14, 14);
assert_eq!(a15, 15);
assert_eq!(a16, 16);
assert_eq!(a17, 17);
assert_eq!(a18, 18);
assert_eq!(a19, 19);
assert_eq!(a20, 20);
}
}
wit_bindgen_wasmtime::import!("../../tests/runtime/many_arguments/exports.wit");
fn run(wasm: &str) -> Result<()> {
let (exports, mut store) = crate::instantiate(
wasm,
|linker| imports::add_to_linker(linker, |cx| -> &mut MyImports { &mut cx.imports }),
|store, module, linker| {
exports::Exports::instantiate(store, module, linker, |cx| &mut cx.exports)
},
)?;
exports.many_arguments(
&mut store, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
)?;
Ok(())
}

View File

@@ -0,0 +1,95 @@
import { addImportsToImports, Imports } from "./imports.js";
import { Exports } from "./exports.js";
import { getWasm, addWasiToImports } from "./helpers.js";
function assertEq(x: any, y: any) {
if (x !== y)
throw new Error(`${x} != ${y}`);
}
function assert(x: boolean) {
if (!x)
throw new Error("assert failed");
}
async function run() {
const importObj = {};
const imports: Imports = {
manyArguments(
a1,
a2,
a3,
a4,
a5,
a6,
a7,
a8,
a9,
a10,
a11,
a12,
a13,
a14,
a15,
a16,
a17,
a18,
a19,
a20,
) {
assertEq(a1, 1n);
assertEq(a2, 2n);
assertEq(a3, 3n);
assertEq(a4, 4n);
assertEq(a5, 5n);
assertEq(a6, 6n);
assertEq(a7, 7n);
assertEq(a8, 8n);
assertEq(a9, 9n);
assertEq(a10, 10n);
assertEq(a11, 11n);
assertEq(a12, 12n);
assertEq(a13, 13n);
assertEq(a14, 14n);
assertEq(a15, 15n);
assertEq(a16, 16n);
assertEq(a17, 17n);
assertEq(a18, 18n);
assertEq(a19, 19n);
assertEq(a20, 20n);
},
};
let instance: WebAssembly.Instance;
addImportsToImports(importObj, imports, name => instance.exports[name]);
const wasi = addWasiToImports(importObj);
const wasm = new Exports();
await wasm.instantiate(getWasm(), importObj);
wasi.start(wasm.instance);
instance = wasm.instance;
wasm.manyArguments(
1n,
2n,
3n,
4n,
5n,
6n,
7n,
8n,
9n,
10n,
11n,
12n,
13n,
14n,
15n,
16n,
17n,
18n,
19n,
20n,
);
}
await run()

View File

@@ -0,0 +1,22 @@
many-arguments: func(
a1: u64,
a2: u64,
a3: u64,
a4: u64,
a5: u64,
a6: u64,
a7: u64,
a8: u64,
a9: u64,
a10: u64,
a11: u64,
a12: u64,
a13: u64,
a14: u64,
a15: u64,
a16: u64,
a17: u64,
a18: u64,
a19: u64,
a20: u64,
)

View File

@@ -0,0 +1,72 @@
#include <assert.h>
#include <exports.h>
#include <imports.h>
#include <limits.h>
#include <math.h>
void exports_many_arguments(
uint64_t a1,
uint64_t a2,
uint64_t a3,
uint64_t a4,
uint64_t a5,
uint64_t a6,
uint64_t a7,
uint64_t a8,
uint64_t a9,
uint64_t a10,
uint64_t a11,
uint64_t a12,
uint64_t a13,
uint64_t a14,
uint64_t a15,
uint64_t a16,
uint64_t a17,
uint64_t a18,
uint64_t a19,
uint64_t a20
) {
assert(a1 == 1);
assert(a2 == 2);
assert(a3 == 3);
assert(a4 == 4);
assert(a5 == 5);
assert(a6 == 6);
assert(a7 == 7);
assert(a8 == 8);
assert(a9 == 9);
assert(a10 == 10);
assert(a11 == 11);
assert(a12 == 12);
assert(a13 == 13);
assert(a14 == 14);
assert(a15 == 15);
assert(a16 == 16);
assert(a17 == 17);
assert(a18 == 18);
assert(a19 == 19);
assert(a20 == 20);
imports_many_arguments(
a1,
a2,
a3,
a4,
a5,
a6,
a7,
a8,
a9,
a10,
a11,
a12,
a13,
a14,
a15,
a16,
a17,
a18,
a19,
a20
);
}

View File

@@ -0,0 +1,56 @@
wit_bindgen_rust::import!("../../tests/runtime/many_arguments/imports.wit");
wit_bindgen_rust::export!("../../tests/runtime/many_arguments/exports.wit");
use imports::*;
struct Exports;
impl exports::Exports for Exports {
fn many_arguments(
a1: u64,
a2: u64,
a3: u64,
a4: u64,
a5: u64,
a6: u64,
a7: u64,
a8: u64,
a9: u64,
a10: u64,
a11: u64,
a12: u64,
a13: u64,
a14: u64,
a15: u64,
a16: u64,
a17: u64,
a18: u64,
a19: u64,
a20: u64,
) {
assert_eq!(a1, 1);
assert_eq!(a2, 2);
assert_eq!(a3, 3);
assert_eq!(a4, 4);
assert_eq!(a5, 5);
assert_eq!(a6, 6);
assert_eq!(a7, 7);
assert_eq!(a8, 8);
assert_eq!(a9, 9);
assert_eq!(a10, 10);
assert_eq!(a11, 11);
assert_eq!(a12, 12);
assert_eq!(a13, 13);
assert_eq!(a14, 14);
assert_eq!(a15, 15);
assert_eq!(a16, 16);
assert_eq!(a17, 17);
assert_eq!(a18, 18);
assert_eq!(a19, 19);
assert_eq!(a20, 20);
many_arguments(
a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19,
a20,
);
}
}

View File

@@ -0,0 +1,16 @@
test-imports: func()
roundtrip-u8: func(a: u8) -> u8
roundtrip-s8: func(a: s8) -> s8
roundtrip-u16: func(a: u16) -> u16
roundtrip-s16: func(a: s16) -> s16
roundtrip-u32: func(a: u32) -> u32
roundtrip-s32: func(a: s32) -> s32
roundtrip-u64: func(a: u64) -> u64
roundtrip-s64: func(a: s64) -> s64
roundtrip-float32: func(a: float32) -> float32
roundtrip-float64: func(a: float64) -> float64
roundtrip-char: func(a: char) -> char
set-scalar: func(a: u32)
get-scalar: func() -> u32

View File

@@ -0,0 +1,106 @@
from exports.bindings import Exports
from imports.bindings import add_imports_to_linker, Imports
import math;
import sys
import wasmtime
class MyImports:
def roundtrip_u8(self, a: int) -> int:
return a
def roundtrip_s8(self, a: int) -> int:
return a
def roundtrip_u16(self, a: int) -> int:
return a
def roundtrip_s16(self, a: int) -> int:
return a
def roundtrip_u32(self, a: int) -> int:
return a
def roundtrip_s32(self, a: int) -> int:
return a
def roundtrip_u64(self, a: int) -> int:
return a
def roundtrip_s64(self, a: int) -> int:
return a
def roundtrip_float32(self, a: float) -> float:
return a
def roundtrip_float64(self, a: float) -> float:
return a
def roundtrip_char(self, a: str) -> str:
return a
def set_scalar(self, a: int) -> None:
self.scalar = a
def get_scalar(self) -> int:
return self.scalar
def run(wasm_file: str) -> None:
store = wasmtime.Store()
module = wasmtime.Module.from_file(store.engine, wasm_file)
linker = wasmtime.Linker(store.engine)
linker.define_wasi()
wasi = wasmtime.WasiConfig()
wasi.inherit_stdout()
wasi.inherit_stderr()
store.set_wasi(wasi)
imports = MyImports()
add_imports_to_linker(linker, store, imports)
wasm = Exports(store, linker, module)
wasm.test_imports(store)
assert(wasm.roundtrip_u8(store, 1) == 1)
assert(wasm.roundtrip_u8(store, (1 << 8) - 1) == (1 << 8) - 1)
assert(wasm.roundtrip_u16(store, 1) == 1)
assert(wasm.roundtrip_u16(store, (1 << 16) - 1) == (1 << 16) - 1)
assert(wasm.roundtrip_u32(store, 1) == 1)
assert(wasm.roundtrip_u32(store, (1 << 32) - 1) == (1 << 32) - 1)
assert(wasm.roundtrip_u64(store, 1) == 1)
assert(wasm.roundtrip_u64(store, (1 << 64) - 1) == (1 << 64) - 1)
assert(wasm.roundtrip_s8(store, 1) == 1)
assert(wasm.roundtrip_s8(store, (1 << (8 - 1) - 1)) == (1 << (8 - 1) - 1))
assert(wasm.roundtrip_s8(store, -(1 << (8 - 1))) == -(1 << (8 - 1)))
assert(wasm.roundtrip_s16(store, 1) == 1)
assert(wasm.roundtrip_s16(store, (1 << (16 - 1) - 1)) == (1 << (16 - 1) - 1))
assert(wasm.roundtrip_s16(store, -(1 << (16 - 1))) == -(1 << (16 - 1)))
assert(wasm.roundtrip_s32(store, 1) == 1)
assert(wasm.roundtrip_s32(store, (1 << (32 - 1) - 1)) == (1 << (32 - 1) - 1))
assert(wasm.roundtrip_s32(store, -(1 << (32 - 1))) == -(1 << (32 - 1)))
assert(wasm.roundtrip_s64(store, 1) == 1)
assert(wasm.roundtrip_s64(store, (1 << (64 - 1) - 1)) == (1 << (64 - 1) - 1))
assert(wasm.roundtrip_s64(store, -(1 << (64 - 1))) == -(1 << (64 - 1)))
inf = float('inf')
assert(wasm.roundtrip_float32(store, 1.0) == 1.0)
assert(wasm.roundtrip_float32(store, inf) == inf)
assert(wasm.roundtrip_float32(store, -inf) == -inf)
assert(math.isnan(wasm.roundtrip_float32(store, float('nan'))))
assert(wasm.roundtrip_float64(store, 1.0) == 1.0)
assert(wasm.roundtrip_float64(store, inf) == inf)
assert(wasm.roundtrip_float64(store, -inf) == -inf)
assert(math.isnan(wasm.roundtrip_float64(store, float('nan'))))
assert(wasm.roundtrip_char(store, 'a') == 'a')
assert(wasm.roundtrip_char(store, ' ') == ' ')
assert(wasm.roundtrip_char(store, '🚩') == '🚩')
wasm.set_scalar(store, 2)
assert(wasm.get_scalar(store) == 2)
wasm.set_scalar(store, 4)
assert(wasm.get_scalar(store) == 4)
if __name__ == '__main__':
run(sys.argv[1])

View File

@@ -0,0 +1,188 @@
use anyhow::Result;
wit_bindgen_wasmtime::export!("../../tests/runtime/numbers/imports.wit");
#[derive(Default)]
pub struct MyImports {
scalar: u32,
}
impl imports::Imports for MyImports {
fn roundtrip_u8(&mut self, val: u8) -> u8 {
val
}
fn roundtrip_s8(&mut self, val: i8) -> i8 {
val
}
fn roundtrip_u16(&mut self, val: u16) -> u16 {
val
}
fn roundtrip_s16(&mut self, val: i16) -> i16 {
val
}
fn roundtrip_u32(&mut self, val: u32) -> u32 {
val
}
fn roundtrip_s32(&mut self, val: i32) -> i32 {
val
}
fn roundtrip_u64(&mut self, val: u64) -> u64 {
val
}
fn roundtrip_s64(&mut self, val: i64) -> i64 {
val
}
fn roundtrip_float32(&mut self, val: f32) -> f32 {
val
}
fn roundtrip_float64(&mut self, val: f64) -> f64 {
val
}
fn roundtrip_char(&mut self, val: char) -> char {
val
}
fn set_scalar(&mut self, val: u32) {
self.scalar = val;
}
fn get_scalar(&mut self) -> u32 {
self.scalar
}
}
wit_bindgen_wasmtime::import!("../../tests/runtime/numbers/exports.wit");
fn run(wasm: &str) -> Result<()> {
let (exports, mut store) = crate::instantiate(
wasm,
|linker| imports::add_to_linker(linker, |cx| -> &mut MyImports { &mut cx.imports }),
|store, module, linker| {
exports::Exports::instantiate(store, module, linker, |cx| &mut cx.exports)
},
)?;
exports.test_imports(&mut store)?;
assert_eq!(exports.roundtrip_u8(&mut store, 1)?, 1);
assert_eq!(
exports.roundtrip_u8(&mut store, u8::min_value())?,
u8::min_value()
);
assert_eq!(
exports.roundtrip_u8(&mut store, u8::max_value())?,
u8::max_value()
);
assert_eq!(exports.roundtrip_s8(&mut store, 1)?, 1);
assert_eq!(
exports.roundtrip_s8(&mut store, i8::min_value())?,
i8::min_value()
);
assert_eq!(
exports.roundtrip_s8(&mut store, i8::max_value())?,
i8::max_value()
);
assert_eq!(exports.roundtrip_u16(&mut store, 1)?, 1);
assert_eq!(
exports.roundtrip_u16(&mut store, u16::min_value())?,
u16::min_value()
);
assert_eq!(
exports.roundtrip_u16(&mut store, u16::max_value())?,
u16::max_value()
);
assert_eq!(exports.roundtrip_s16(&mut store, 1)?, 1);
assert_eq!(
exports.roundtrip_s16(&mut store, i16::min_value())?,
i16::min_value()
);
assert_eq!(
exports.roundtrip_s16(&mut store, i16::max_value())?,
i16::max_value()
);
assert_eq!(exports.roundtrip_u32(&mut store, 1)?, 1);
assert_eq!(
exports.roundtrip_u32(&mut store, u32::min_value())?,
u32::min_value()
);
assert_eq!(
exports.roundtrip_u32(&mut store, u32::max_value())?,
u32::max_value()
);
assert_eq!(exports.roundtrip_s32(&mut store, 1)?, 1);
assert_eq!(
exports.roundtrip_s32(&mut store, i32::min_value())?,
i32::min_value()
);
assert_eq!(
exports.roundtrip_s32(&mut store, i32::max_value())?,
i32::max_value()
);
assert_eq!(exports.roundtrip_u64(&mut store, 1)?, 1);
assert_eq!(
exports.roundtrip_u64(&mut store, u64::min_value())?,
u64::min_value()
);
assert_eq!(
exports.roundtrip_u64(&mut store, u64::max_value())?,
u64::max_value()
);
assert_eq!(exports.roundtrip_s64(&mut store, 1)?, 1);
assert_eq!(
exports.roundtrip_s64(&mut store, i64::min_value())?,
i64::min_value()
);
assert_eq!(
exports.roundtrip_s64(&mut store, i64::max_value())?,
i64::max_value()
);
assert_eq!(exports.roundtrip_float32(&mut store, 1.0)?, 1.0);
assert_eq!(
exports.roundtrip_float32(&mut store, f32::INFINITY)?,
f32::INFINITY
);
assert_eq!(
exports.roundtrip_float32(&mut store, f32::NEG_INFINITY)?,
f32::NEG_INFINITY
);
assert!(exports.roundtrip_float32(&mut store, f32::NAN)?.is_nan());
assert_eq!(exports.roundtrip_float64(&mut store, 1.0)?, 1.0);
assert_eq!(
exports.roundtrip_float64(&mut store, f64::INFINITY)?,
f64::INFINITY
);
assert_eq!(
exports.roundtrip_float64(&mut store, f64::NEG_INFINITY)?,
f64::NEG_INFINITY
);
assert!(exports.roundtrip_float64(&mut store, f64::NAN)?.is_nan());
assert_eq!(exports.roundtrip_char(&mut store, 'a')?, 'a');
assert_eq!(exports.roundtrip_char(&mut store, ' ')?, ' ');
assert_eq!(exports.roundtrip_char(&mut store, '🚩')?, '🚩');
exports.set_scalar(&mut store, 2)?;
assert_eq!(exports.get_scalar(&mut store)?, 2);
exports.set_scalar(&mut store, 4)?;
assert_eq!(exports.get_scalar(&mut store)?, 4);
Ok(())
}

View File

@@ -0,0 +1,89 @@
import { addImportsToImports, Imports } from "./imports.js";
import { Exports } from "./exports.js";
import { getWasm, addWasiToImports } from "./helpers.js";
function assertEq(x: any, y: any) {
if (x !== y)
throw new Error(`${x} != ${y}`);
}
function assert(x: boolean) {
if (!x)
throw new Error("assert failed");
}
async function run() {
const importObj = {};
let scalar = 0;
addImportsToImports(importObj, {
roundtripU8(x) { return x; },
roundtripS8(x) { return x; },
roundtripU16(x) { return x; },
roundtripS16(x) { return x; },
roundtripU32(x) { return x; },
roundtripS32(x) { return x; },
roundtripU64(x) { return x; },
roundtripS64(x) { return x; },
roundtripFloat32(x) { return x; },
roundtripFloat64(x) { return x; },
roundtripChar(x) { return x; },
setScalar(x) { scalar = x; },
getScalar() { return scalar; },
});
const wasi = addWasiToImports(importObj);
const wasm = new Exports();
await wasm.instantiate(getWasm(), importObj);
wasi.start(wasm.instance);
wasm.testImports();
assertEq(wasm.roundtripU8(1), 1);
assertEq(wasm.roundtripU8((1 << 8) - 1), (1 << 8) - 1);
assertEq(wasm.roundtripS8(1), 1);
assertEq(wasm.roundtripS8((1 << 7) - 1), (1 << 7) - 1);
assertEq(wasm.roundtripS8(-(1 << 7)), -(1 << 7));
assertEq(wasm.roundtripU16(1), 1);
assertEq(wasm.roundtripU16((1 << 16) - 1), (1 << 16) - 1);
assertEq(wasm.roundtripS16(1), 1);
assertEq(wasm.roundtripS16((1 << 15) - 1), (1 << 15) - 1);
assertEq(wasm.roundtripS16(-(1 << 15)), -(1 << 15));
assertEq(wasm.roundtripU32(1), 1);
assertEq(wasm.roundtripU32(~0 >>> 0), ~0 >>> 0);
assertEq(wasm.roundtripS32(1), 1);
assertEq(wasm.roundtripS32(((1 << 31) - 1) >>> 0), ((1 << 31) - 1) >>> 0);
assertEq(wasm.roundtripS32(1 << 31), 1 << 31);
assertEq(wasm.roundtripU64(1n), 1n);
assertEq(wasm.roundtripU64((1n << 64n) - 1n), (1n << 64n) - 1n);
assertEq(wasm.roundtripS64(1n), 1n);
assertEq(wasm.roundtripS64((1n << 63n) - 1n), (1n << 63n) - 1n);
assertEq(wasm.roundtripS64(-(1n << 63n)), -(1n << 63n));
assertEq(wasm.roundtripFloat32(1), 1);
assertEq(wasm.roundtripFloat32(Infinity), Infinity);
assertEq(wasm.roundtripFloat32(-Infinity), -Infinity);
assert(Number.isNaN(wasm.roundtripFloat32(NaN)));
assertEq(wasm.roundtripFloat64(1), 1);
assertEq(wasm.roundtripFloat64(Infinity), Infinity);
assertEq(wasm.roundtripFloat64(-Infinity), -Infinity);
assert(Number.isNaN(wasm.roundtripFloat64(NaN)));
assertEq(wasm.roundtripChar('a'), 'a');
assertEq(wasm.roundtripChar(' '), ' ');
assertEq(wasm.roundtripChar('🚩'), '🚩');
wasm.setScalar(2);
assertEq(wasm.getScalar(), 2);
wasm.setScalar(4);
assertEq(wasm.getScalar(), 4);
}
await run()

View File

@@ -0,0 +1,14 @@
roundtrip-u8: func(a: u8) -> u8
roundtrip-s8: func(a: s8) -> s8
roundtrip-u16: func(a: u16) -> u16
roundtrip-s16: func(a: s16) -> s16
roundtrip-u32: func(a: u32) -> u32
roundtrip-s32: func(a: s32) -> s32
roundtrip-u64: func(a: u64) -> u64
roundtrip-s64: func(a: s64) -> s64
roundtrip-float32: func(a: float32) -> float32
roundtrip-float64: func(a: float64) -> float64
roundtrip-char: func(a: char) -> char
set-scalar: func(a: u32)
get-scalar: func() -> u32

View File

@@ -0,0 +1,113 @@
#include <assert.h>
#include <exports.h>
#include <imports.h>
#include <limits.h>
#include <math.h>
uint8_t exports_roundtrip_u8(uint8_t a) {
return a;
}
int8_t exports_roundtrip_s8(int8_t a) {
return a;
}
uint16_t exports_roundtrip_u16(uint16_t a) {
return a;
}
int16_t exports_roundtrip_s16(int16_t a) {
return a;
}
uint32_t exports_roundtrip_u32(uint32_t a) {
return a;
}
int32_t exports_roundtrip_s32(int32_t a) {
return a;
}
uint64_t exports_roundtrip_u64(uint64_t a) {
return a;
}
int64_t exports_roundtrip_s64(int64_t a) {
return a;
}
float exports_roundtrip_float32(float a) {
return a;
}
double exports_roundtrip_float64(double a) {
return a;
}
uint32_t exports_roundtrip_char(uint32_t a) {
return a;
}
static uint32_t SCALAR = 0;
void exports_set_scalar(uint32_t a) {
SCALAR = a;
}
uint32_t exports_get_scalar(void) {
return SCALAR;
}
void exports_test_imports() {
assert(imports_roundtrip_u8(1) == 1);
assert(imports_roundtrip_u8(0) == 0);
assert(imports_roundtrip_u8(UCHAR_MAX) == UCHAR_MAX);
assert(imports_roundtrip_s8(1) == 1);
assert(imports_roundtrip_s8(SCHAR_MIN) == SCHAR_MIN);
assert(imports_roundtrip_s8(SCHAR_MAX) == SCHAR_MAX);
assert(imports_roundtrip_u16(1) == 1);
assert(imports_roundtrip_u16(0) == 0);
assert(imports_roundtrip_u16(USHRT_MAX) == USHRT_MAX);
assert(imports_roundtrip_s16(1) == 1);
assert(imports_roundtrip_s16(SHRT_MIN) == SHRT_MIN);
assert(imports_roundtrip_s16(SHRT_MAX) == SHRT_MAX);
assert(imports_roundtrip_u32(1) == 1);
assert(imports_roundtrip_u32(0) == 0);
assert(imports_roundtrip_u32(UINT_MAX) == UINT_MAX);
assert(imports_roundtrip_s32(1) == 1);
assert(imports_roundtrip_s32(INT_MIN) == INT_MIN);
assert(imports_roundtrip_s32(INT_MAX) == INT_MAX);
assert(imports_roundtrip_u64(1) == 1);
assert(imports_roundtrip_u64(0) == 0);
assert(imports_roundtrip_u64(ULONG_MAX) == ULONG_MAX);
assert(imports_roundtrip_s64(1) == 1);
assert(imports_roundtrip_s64(LONG_MIN) == LONG_MIN);
assert(imports_roundtrip_s64(LONG_MAX) == LONG_MAX);
assert(imports_roundtrip_float32(1.0) == 1.0);
assert(imports_roundtrip_float32(INFINITY) == INFINITY);
assert(imports_roundtrip_float32(-INFINITY) == -INFINITY);
assert(isnan(imports_roundtrip_float32(NAN)));
assert(imports_roundtrip_float64(1.0) == 1.0);
assert(imports_roundtrip_float64(INFINITY) == INFINITY);
assert(imports_roundtrip_float64(-INFINITY) == -INFINITY);
assert(isnan(imports_roundtrip_float64(NAN)));
assert(imports_roundtrip_char('a') == 'a');
assert(imports_roundtrip_char(' ') == ' ');
assert(imports_roundtrip_char(U'🚩') == U'🚩');
imports_set_scalar(2);
assert(imports_get_scalar() == 2);
imports_set_scalar(4);
assert(imports_get_scalar() == 4);
}

View File

@@ -0,0 +1,116 @@
wit_bindgen_rust::import!("../../tests/runtime/numbers/imports.wit");
wit_bindgen_rust::export!("../../tests/runtime/numbers/exports.wit");
use imports::*;
use std::sync::atomic::{AtomicU32, Ordering::SeqCst};
struct Exports;
static SCALAR: AtomicU32 = AtomicU32::new(0);
impl exports::Exports for Exports {
fn test_imports() {
assert_eq!(roundtrip_u8(1), 1);
assert_eq!(roundtrip_u8(u8::min_value()), u8::min_value());
assert_eq!(roundtrip_u8(u8::max_value()), u8::max_value());
assert_eq!(roundtrip_s8(1), 1);
assert_eq!(roundtrip_s8(i8::min_value()), i8::min_value());
assert_eq!(roundtrip_s8(i8::max_value()), i8::max_value());
assert_eq!(roundtrip_u16(1), 1);
assert_eq!(roundtrip_u16(u16::min_value()), u16::min_value());
assert_eq!(roundtrip_u16(u16::max_value()), u16::max_value());
assert_eq!(roundtrip_s16(1), 1);
assert_eq!(roundtrip_s16(i16::min_value()), i16::min_value());
assert_eq!(roundtrip_s16(i16::max_value()), i16::max_value());
assert_eq!(roundtrip_u32(1), 1);
assert_eq!(roundtrip_u32(u32::min_value()), u32::min_value());
assert_eq!(roundtrip_u32(u32::max_value()), u32::max_value());
assert_eq!(roundtrip_s32(1), 1);
assert_eq!(roundtrip_s32(i32::min_value()), i32::min_value());
assert_eq!(roundtrip_s32(i32::max_value()), i32::max_value());
assert_eq!(roundtrip_u64(1), 1);
assert_eq!(roundtrip_u64(u64::min_value()), u64::min_value());
assert_eq!(roundtrip_u64(u64::max_value()), u64::max_value());
assert_eq!(roundtrip_s64(1), 1);
assert_eq!(roundtrip_s64(i64::min_value()), i64::min_value());
assert_eq!(roundtrip_s64(i64::max_value()), i64::max_value());
assert_eq!(roundtrip_float32(1.0), 1.0);
assert_eq!(roundtrip_float32(f32::INFINITY), f32::INFINITY);
assert_eq!(roundtrip_float32(f32::NEG_INFINITY), f32::NEG_INFINITY);
assert!(roundtrip_float32(f32::NAN).is_nan());
assert_eq!(roundtrip_float64(1.0), 1.0);
assert_eq!(roundtrip_float64(f64::INFINITY), f64::INFINITY);
assert_eq!(roundtrip_float64(f64::NEG_INFINITY), f64::NEG_INFINITY);
assert!(roundtrip_float64(f64::NAN).is_nan());
assert_eq!(roundtrip_char('a'), 'a');
assert_eq!(roundtrip_char(' '), ' ');
assert_eq!(roundtrip_char('🚩'), '🚩');
set_scalar(2);
assert_eq!(get_scalar(), 2);
set_scalar(4);
assert_eq!(get_scalar(), 4);
}
fn roundtrip_u8(a: u8) -> u8 {
a
}
fn roundtrip_s8(a: i8) -> i8 {
a
}
fn roundtrip_u16(a: u16) -> u16 {
a
}
fn roundtrip_s16(a: i16) -> i16 {
a
}
fn roundtrip_u32(a: u32) -> u32 {
a
}
fn roundtrip_s32(a: i32) -> i32 {
a
}
fn roundtrip_u64(a: u64) -> u64 {
a
}
fn roundtrip_s64(a: i64) -> i64 {
a
}
fn roundtrip_float32(a: f32) -> f32 {
a
}
fn roundtrip_float64(a: f64) -> f64 {
a
}
fn roundtrip_char(a: char) -> char {
a
}
fn set_scalar(val: u32) {
SCALAR.store(val, SeqCst)
}
fn get_scalar() -> u32 {
SCALAR.load(SeqCst)
}
}

View File

@@ -0,0 +1,46 @@
test-imports: func()
multiple-results: func() -> tuple<u8, u16>
swap-tuple: func(a: tuple<u8, u32>) -> tuple<u32, u8>
flags f1 { a, b }
roundtrip-flags1: func(a: f1) -> f1
flags f2 { c, d, e }
roundtrip-flags2: func(a: f2) -> f2
flags f8 {
b0, b1, b2, b3, b4, b5, b6, b7,
}
flags f16 {
b0, b1, b2, b3, b4, b5, b6, b7,
b8, b9, b10, b11, b12, b13, b14, b15,
}
flags f32 {
b0, b1, b2, b3, b4, b5, b6, b7,
b8, b9, b10, b11, b12, b13, b14, b15,
b16, b17, b18, b19, b20, b21, b22, b23,
b24, b25, b26, b27, b28, b29, b30, b31,
}
flags f64 {
b0, b1, b2, b3, b4, b5, b6, b7,
b8, b9, b10, b11, b12, b13, b14, b15,
b16, b17, b18, b19, b20, b21, b22, b23,
b24, b25, b26, b27, b28, b29, b30, b31,
b32, b33, b34, b35, b36, b37, b38, b39,
b40, b41, b42, b43, b44, b45, b46, b47,
b48, b49, b50, b51, b52, b53, b54, b55,
b56, b57, b58, b59, b60, b61, b62, b63,
}
roundtrip-flags3: func(a: f8, b: f16, c: f32, d: f64) -> tuple<f8, f16, f32, f64>
record r1 { a: u8, b: f1 }
roundtrip-record1: func(a: r1) -> r1
tuple0: func(a: tuple<>) -> tuple<>
tuple1: func(a: tuple<u8>) -> tuple<u8>

View File

@@ -0,0 +1,72 @@
from exports.bindings import Exports
from imports.bindings import add_imports_to_linker, Imports
from typing import Tuple
import exports.bindings as e
import imports.bindings as i
import sys
import wasmtime
class MyImports:
def multiple_results(self) -> Tuple[int, int]:
return (4, 5)
def swap_tuple(self, a: Tuple[int, int]) -> Tuple[int, int]:
return (a[1], a[0])
def roundtrip_flags1(self, a: i.F1) -> i.F1:
return a
def roundtrip_flags2(self, a: i.F2) -> i.F2:
return a
def roundtrip_flags3(self, a: i.Flag8, b: i.Flag16, c: i.Flag32, d: i.Flag64) -> Tuple[i.Flag8, i.Flag16, i.Flag32, i.Flag64]:
return (a, b, c, d)
def roundtrip_record1(self, a: i.R1) -> i.R1:
return a
def tuple0(self, a: None) -> None:
pass
def tuple1(self, a: Tuple[int]) -> Tuple[int]:
return (a[0],)
def run(wasm_file: str) -> None:
store = wasmtime.Store()
module = wasmtime.Module.from_file(store.engine, wasm_file)
linker = wasmtime.Linker(store.engine)
linker.define_wasi()
wasi = wasmtime.WasiConfig()
wasi.inherit_stdout()
wasi.inherit_stderr()
store.set_wasi(wasi)
imports = MyImports()
add_imports_to_linker(linker, store, imports)
wasm = Exports(store, linker, module)
wasm.test_imports(store)
assert(wasm.multiple_results(store) == (100, 200))
assert(wasm.swap_tuple(store, (1, 2)) == (2, 1))
assert(wasm.roundtrip_flags1(store, e.F1.A) == e.F1.A)
assert(wasm.roundtrip_flags1(store, e.F1(0)) == e.F1(0))
assert(wasm.roundtrip_flags1(store, e.F1.A | e.F1.B) == (e.F1.A | e.F1.B))
assert(wasm.roundtrip_flags2(store, e.F2.C) == e.F2.C)
assert(wasm.roundtrip_flags2(store, e.F2(0)) == e.F2(0))
assert(wasm.roundtrip_flags2(store, e.F2.D) == e.F2.D)
assert(wasm.roundtrip_flags2(store, e.F2.C | e.F2.E) == (e.F2.C | e.F2.E))
r = wasm.roundtrip_record1(store, e.R1(8, e.F1(0)))
assert(r.a == 8)
assert(r.b == e.F1(0))
r = wasm.roundtrip_record1(store, e.R1(a=0, b=e.F1.A | e.F1.B))
assert(r.a == 0)
assert(r.b == (e.F1.A | e.F1.B))
wasm.tuple0(store, None)
assert(wasm.tuple1(store, (1,)) == (1,))
if __name__ == '__main__':
run(sys.argv[1])

View File

@@ -0,0 +1,111 @@
use anyhow::Result;
wit_bindgen_wasmtime::export!("../../tests/runtime/records/imports.wit");
use imports::*;
#[derive(Default)]
pub struct MyImports;
impl Imports for MyImports {
fn multiple_results(&mut self) -> (u8, u16) {
(4, 5)
}
fn swap_tuple(&mut self, a: (u8, u32)) -> (u32, u8) {
(a.1, a.0)
}
fn roundtrip_flags1(&mut self, a: F1) -> F1 {
drop(a.to_string());
drop(format!("{:?}", a));
drop(a & F1::all());
a
}
fn roundtrip_flags2(&mut self, a: F2) -> F2 {
a
}
fn roundtrip_flags3(
&mut self,
a: Flag8,
b: Flag16,
c: Flag32,
d: Flag64,
) -> (Flag8, Flag16, Flag32, Flag64) {
(a, b, c, d)
}
fn roundtrip_record1(&mut self, a: R1) -> R1 {
drop(format!("{:?}", a));
a
}
fn tuple0(&mut self, _: ()) {}
fn tuple1(&mut self, a: (u8,)) -> (u8,) {
(a.0,)
}
}
wit_bindgen_wasmtime::import!("../../tests/runtime/records/exports.wit");
fn run(wasm: &str) -> Result<()> {
use exports::*;
let (exports, mut store) = crate::instantiate(
wasm,
|linker| imports::add_to_linker(linker, |cx| -> &mut MyImports { &mut cx.imports }),
|store, module, linker| Exports::instantiate(store, module, linker, |cx| &mut cx.exports),
)?;
exports.test_imports(&mut store)?;
assert_eq!(exports.multiple_results(&mut store,)?, (100, 200));
assert_eq!(exports.swap_tuple(&mut store, (1u8, 2u32))?, (2u32, 1u8));
assert_eq!(exports.roundtrip_flags1(&mut store, F1::A)?, F1::A);
assert_eq!(
exports.roundtrip_flags1(&mut store, F1::empty())?,
F1::empty()
);
assert_eq!(exports.roundtrip_flags1(&mut store, F1::B)?, F1::B);
assert_eq!(
exports.roundtrip_flags1(&mut store, F1::A | F1::B)?,
F1::A | F1::B
);
assert_eq!(exports.roundtrip_flags2(&mut store, F2::C)?, F2::C);
assert_eq!(
exports.roundtrip_flags2(&mut store, F2::empty())?,
F2::empty()
);
assert_eq!(exports.roundtrip_flags2(&mut store, F2::D)?, F2::D);
assert_eq!(
exports.roundtrip_flags2(&mut store, F2::C | F2::E)?,
F2::C | F2::E
);
let r = exports.roundtrip_record1(
&mut store,
R1 {
a: 8,
b: F1::empty(),
},
)?;
assert_eq!(r.a, 8);
assert_eq!(r.b, F1::empty());
let r = exports.roundtrip_record1(
&mut store,
R1 {
a: 0,
b: F1::A | F1::B,
},
)?;
assert_eq!(r.a, 0);
assert_eq!(r.b, F1::A | F1::B);
assert_eq!(exports.tuple0(&mut store, ())?, ());
assert_eq!(exports.tuple1(&mut store, (1,))?, (1,));
Ok(())
}

View File

@@ -0,0 +1,57 @@
import { addImportsToImports, Imports } from "./imports.js";
import { Exports } from "./exports.js";
import * as exports from "./exports.js";
import { getWasm, addWasiToImports } from "./helpers.js";
// @ts-ignore
import * as assert from 'assert';
async function run() {
const importObj = {};
const imports: Imports = {
multipleResults() { return [4, 5]; },
swapTuple([a, b]) { return [b, a]; },
roundtripFlags1(x) { return x; },
roundtripFlags2(x) { return x; },
roundtripFlags3(r0, r1, r2, r3) { return [r0, r1, r2, r3]; },
roundtripRecord1(x) { return x; },
tuple0([]) { return []; },
tuple1([x]) { return [x]; },
};
let instance: WebAssembly.Instance;
addImportsToImports(importObj, imports, name => instance.exports[name]);
const wasi = addWasiToImports(importObj);
const wasm = new Exports();
await wasm.instantiate(getWasm(), importObj);
wasi.start(wasm.instance);
instance = wasm.instance;
wasm.testImports();
assert.deepEqual(wasm.multipleResults(), [100, 200]);
assert.deepStrictEqual(wasm.swapTuple([1, 2]), [2, 1]);
assert.deepEqual(wasm.roundtripFlags1(exports.F1_A), exports.F1_A);
assert.deepEqual(wasm.roundtripFlags1(0), 0);
assert.deepEqual(wasm.roundtripFlags1(exports.F1_A | exports.F1_B), exports.F1_A | exports.F1_B);
assert.deepEqual(wasm.roundtripFlags2(exports.F2_C), exports.F2_C);
assert.deepEqual(wasm.roundtripFlags2(0), 0);
assert.deepEqual(wasm.roundtripFlags2(exports.F2_D), exports.F2_D);
assert.deepEqual(wasm.roundtripFlags2(exports.F2_C | exports.F2_E), exports.F2_C | exports.F2_E);
{
const { a, b } = wasm.roundtripRecord1({ a: 8, b: 0 });
assert.deepEqual(a, 8);
assert.deepEqual(b, 0);
}
{
const { a, b } = wasm.roundtripRecord1({ a: 0, b: exports.F1_A | exports.F1_B });
assert.deepEqual(a, 0);
assert.deepEqual(b, exports.F1_A | exports.F1_B);
}
assert.deepStrictEqual(wasm.tuple0([]), []);
assert.deepStrictEqual(wasm.tuple1([1]), [1]);
}
await run()

View File

@@ -0,0 +1,44 @@
multiple-results: func() -> tuple<u8, u16>
swap-tuple: func(a: tuple<u8, u32>) -> tuple<u32, u8>
flags f1 { a, b }
roundtrip-flags1: func(a: f1) -> f1
flags f2 { c, d, e }
roundtrip-flags2: func(a: f2) -> f2
flags flag8 {
b0, b1, b2, b3, b4, b5, b6, b7,
}
flags flag16 {
b0, b1, b2, b3, b4, b5, b6, b7,
b8, b9, b10, b11, b12, b13, b14, b15,
}
flags flag32 {
b0, b1, b2, b3, b4, b5, b6, b7,
b8, b9, b10, b11, b12, b13, b14, b15,
b16, b17, b18, b19, b20, b21, b22, b23,
b24, b25, b26, b27, b28, b29, b30, b31,
}
flags flag64 {
b0, b1, b2, b3, b4, b5, b6, b7,
b8, b9, b10, b11, b12, b13, b14, b15,
b16, b17, b18, b19, b20, b21, b22, b23,
b24, b25, b26, b27, b28, b29, b30, b31,
b32, b33, b34, b35, b36, b37, b38, b39,
b40, b41, b42, b43, b44, b45, b46, b47,
b48, b49, b50, b51, b52, b53, b54, b55,
b56, b57, b58, b59, b60, b61, b62, b63,
}
roundtrip-flags3: func(a: flag8, b: flag16, c: flag32, d: flag64) -> tuple<flag8, flag16, flag32, flag64>
record r1 { a: u8, b: f1 }
roundtrip-record1: func(a: r1) -> r1
tuple0: func(a: tuple<>) -> tuple<>
tuple1: func(a: tuple<u8>) -> tuple<u8>

View File

@@ -0,0 +1,106 @@
#include <assert.h>
#include <imports.h>
#include <exports.h>
void exports_test_imports() {
{
uint8_t a;
uint16_t b;
imports_multiple_results(&a, &b);
assert(a == 4);
assert(b == 5);
}
imports_tuple2_u8_u32_t input;
input.f0 = 1;
input.f1 = 2;
uint32_t a;
uint8_t b;
imports_swap_tuple(&input, &a, &b);
assert(a == 2);
assert(b == 1);
assert(imports_roundtrip_flags1(IMPORTS_F1_A) == IMPORTS_F1_A);
assert(imports_roundtrip_flags1(0) == 0);
assert(imports_roundtrip_flags1(IMPORTS_F1_B) == IMPORTS_F1_B);
assert(imports_roundtrip_flags1(IMPORTS_F1_A | IMPORTS_F1_B) == (IMPORTS_F1_A | IMPORTS_F1_B));
assert(imports_roundtrip_flags2(IMPORTS_F2_C) == IMPORTS_F2_C);
assert(imports_roundtrip_flags2(0) == 0);
assert(imports_roundtrip_flags2(IMPORTS_F2_D) == IMPORTS_F2_D);
assert(imports_roundtrip_flags2(IMPORTS_F2_C | IMPORTS_F2_E) == (IMPORTS_F2_C | IMPORTS_F2_E));
imports_flag8_t flag8;
imports_flag16_t flag16;
imports_flag32_t flag32;
imports_flag64_t flag64;
imports_roundtrip_flags3(IMPORTS_FLAG8_B0, IMPORTS_FLAG16_B1, IMPORTS_FLAG32_B2, IMPORTS_FLAG64_B3,
&flag8, &flag16, &flag32, &flag64);
assert(flag8 == IMPORTS_FLAG8_B0);
assert(flag16 == IMPORTS_FLAG16_B1);
assert(flag32 == IMPORTS_FLAG32_B2);
assert(flag64 == IMPORTS_FLAG64_B3);
{
imports_r1_t a, b;
a.a = 8;
a.b = 0;
imports_roundtrip_record1(&a, &b);
assert(b.a == 8);
assert(b.b == 0);
}
{
imports_r1_t a, b;
a.a = 0;
a.b = IMPORTS_F1_A | IMPORTS_F1_B;
imports_roundtrip_record1(&a, &b);
assert(b.a == 0);
assert(b.b == (IMPORTS_F1_A | IMPORTS_F1_B));
}
imports_tuple0_t t0;
imports_tuple0(&t0);
imports_tuple1_u8_t t1;
t1.f0 = 1;
uint8_t ret;
imports_tuple1(&t1, &ret);
assert(ret == 1);
}
void exports_multiple_results(uint8_t *ret0, uint16_t *ret1) {
*ret0 = 100;
*ret1 = 200;
}
void exports_swap_tuple(exports_tuple2_u8_u32_t *a, uint32_t *ret0, uint8_t *ret1) {
*ret0 = a->f1;
*ret1 = a->f0;
}
exports_f1_t exports_roundtrip_flags1(exports_f1_t a) {
return a;
}
exports_f2_t exports_roundtrip_flags2(exports_f2_t a) {
return a;
}
void exports_roundtrip_flags3(exports_f8_t a, exports_f16_t b, exports_f32_t c, exports_f64_t d, exports_f8_t *ret0, exports_f16_t *ret1, exports_f32_t *ret2, exports_f64_t *ret3) {
*ret0 = a;
*ret1 = b;
*ret2 = c;
*ret3 = d;
}
void exports_roundtrip_record1(exports_r1_t *a, exports_r1_t *ret0) {
*ret0 = *a;
}
void exports_tuple0(exports_tuple0_t *a) {
}
void exports_tuple1(exports_tuple1_u8_t *a, uint8_t *ret0) {
*ret0 = a->f0;
}

View File

@@ -0,0 +1,77 @@
wit_bindgen_rust::import!("../../tests/runtime/records/imports.wit");
wit_bindgen_rust::export!("../../tests/runtime/records/exports.wit");
use exports::*;
struct Exports;
impl exports::Exports for Exports {
fn test_imports() {
use imports::*;
assert_eq!(multiple_results(), (4, 5));
assert_eq!(swap_tuple((1u8, 2u32)), (2u32, 1u8));
assert_eq!(roundtrip_flags1(F1::A), F1::A);
assert_eq!(roundtrip_flags1(F1::empty()), F1::empty());
assert_eq!(roundtrip_flags1(F1::B), F1::B);
assert_eq!(roundtrip_flags1(F1::A | F1::B), F1::A | F1::B);
assert_eq!(roundtrip_flags2(F2::C), F2::C);
assert_eq!(roundtrip_flags2(F2::empty()), F2::empty());
assert_eq!(roundtrip_flags2(F2::D), F2::D);
assert_eq!(roundtrip_flags2(F2::C | F2::E), F2::C | F2::E);
assert_eq!(
roundtrip_flags3(Flag8::B0, Flag16::B1, Flag32::B2, Flag64::B3),
(Flag8::B0, Flag16::B1, Flag32::B2, Flag64::B3)
);
let r = roundtrip_record1(R1 {
a: 8,
b: F1::empty(),
});
assert_eq!(r.a, 8);
assert_eq!(r.b, F1::empty());
let r = roundtrip_record1(R1 {
a: 0,
b: F1::A | F1::B,
});
assert_eq!(r.a, 0);
assert_eq!(r.b, F1::A | F1::B);
assert_eq!(tuple0(()), ());
assert_eq!(tuple1((1,)), (1,));
}
fn multiple_results() -> (u8, u16) {
(100, 200)
}
fn swap_tuple(a: (u8, u32)) -> (u32, u8) {
(a.1, a.0)
}
fn roundtrip_flags1(a: F1) -> F1 {
a
}
fn roundtrip_flags2(a: F2) -> F2 {
a
}
fn roundtrip_flags3(a: F8, b: F16, c: F32, d: F64) -> (F8, F16, F32, F64) {
(a, b, c, d)
}
fn roundtrip_record1(a: R1) -> R1 {
a
}
fn tuple0(_: ()) {}
fn tuple1(a: (u8,)) -> (u8,) {
(a.0,)
}
}

View File

@@ -0,0 +1 @@
thunk: func()

View File

@@ -0,0 +1,27 @@
from exports.bindings import Exports
from imports.bindings import add_imports_to_linker, Imports
import sys
import wasmtime
class MyImports:
def thunk(self) -> None:
self.hit = True
def run(wasm_file: str) -> None:
store = wasmtime.Store()
module = wasmtime.Module.from_file(store.engine, wasm_file)
linker = wasmtime.Linker(store.engine)
linker.define_wasi()
wasi = wasmtime.WasiConfig()
wasi.inherit_stdout()
wasi.inherit_stderr()
store.set_wasi(wasi)
imports = MyImports()
add_imports_to_linker(linker, store, imports)
wasm = Exports(store, linker, module)
wasm.thunk(store)
assert(imports.hit)
if __name__ == '__main__':
run(sys.argv[1])

View File

@@ -0,0 +1,33 @@
use anyhow::Result;
wit_bindgen_wasmtime::export!("../../tests/runtime/smoke/imports.wit");
#[derive(Default)]
pub struct MyImports {
hit: bool,
}
impl imports::Imports for MyImports {
fn thunk(&mut self) {
self.hit = true;
println!("in the host");
}
}
wit_bindgen_wasmtime::import!("../../tests/runtime/smoke/exports.wit");
fn run(wasm: &str) -> Result<()> {
let (exports, mut store) = crate::instantiate(
wasm,
|linker| imports::add_to_linker(linker, |cx| -> &mut MyImports { &mut cx.imports }),
|store, module, linker| {
exports::Exports::instantiate(store, module, linker, |cx| &mut cx.exports)
},
)?;
exports.thunk(&mut store)?;
assert!(store.data().imports.hit);
Ok(())
}

View File

@@ -0,0 +1,28 @@
import { addImportsToImports, Imports } from "./imports.js";
import { Exports } from "./exports.js";
import { getWasm, addWasiToImports } from "./helpers.js";
function assert(x: boolean, msg: string) {
if (!x)
throw new Error(msg);
}
async function run() {
const importObj = {};
let hit = false;
addImportsToImports(importObj, {
thunk() {
hit = true;
}
});
const wasi = addWasiToImports(importObj);
const wasm = new Exports();
await wasm.instantiate(getWasm(), importObj);
wasi.start(wasm.instance);
wasm.thunk();
assert(hit, "import not called");
}
await run()

View File

@@ -0,0 +1 @@
thunk: func()

View File

@@ -0,0 +1,6 @@
#include <imports.h>
#include <exports.h>
void exports_thunk() {
imports_thunk();
}

View File

@@ -0,0 +1,10 @@
wit_bindgen_rust::import!("../../tests/runtime/smoke/imports.wit");
wit_bindgen_rust::export!("../../tests/runtime/smoke/exports.wit");
struct Exports;
impl exports::Exports for Exports {
fn thunk() {
imports::thunk();
}
}

View File

@@ -0,0 +1,12 @@
test-imports: func()
f1: func()
f2: func(a: u32)
f3: func(a: u32, b: u32)
f4: func() -> u32
// TODO: shoudl re-enable when re-implemented
//f5: func() -> tuple<u32, u32>
//
//f6: func(a: u32, b: u32, c: u32) -> tuple<u32, u32, u32>

View File

@@ -0,0 +1,127 @@
use anyhow::Context;
wit_bindgen_wasmtime::export!("../../tests/runtime/smw_functions/imports.wit");
#[derive(Default)]
pub struct Host {
pub f1_called: bool,
pub f2_arg: u32,
pub f3_a: u32,
pub f3_b: u32,
pub f4_called: bool,
// pub f5_called: bool,
// pub f6_a: u32,
// pub f6_b: u32,
// pub f6_c: u32,
}
impl imports::Imports for Host {
fn f1(&mut self) {
self.f1_called = true;
}
fn f2(&mut self, arg: u32) {
self.f2_arg = arg;
}
fn f3(&mut self, a: u32, b: u32) {
self.f3_a = a;
self.f3_b = b;
}
fn f4(&mut self) -> u32 {
self.f4_called = true;
1337
}
// fn f5(&mut self) -> (u32, u32) {
// self.f5_called = true;
// (1, 2)
// }
// fn f6(&mut self, a: u32, b: u32, c: u32) -> (u32, u32, u32) {
// self.f6_a = a;
// self.f6_b = b;
// self.f6_c = c;
// (a + 1, b + 1, c + 1)
// }
}
wit_bindgen_wasmtime::import!("../../tests/runtime/smw_functions/exports.wit");
fn run(wasm: &str) -> anyhow::Result<()> {
let (exports, mut store) = crate::instantiate_smw(
wasm,
|linker| imports::add_to_linker(linker, |cx| -> &mut Host { &mut cx.imports }),
|store, module, linker| {
exports::Exports::instantiate(store, module, linker, |cx| &mut cx.exports)
},
)?;
// Test that the import instance called the functions we made available with
// the expected arguments.
exports.test_imports(&mut store)?;
assert!(
store.data().imports.f1_called,
"top-level JS imported and called `f1`",
);
assert_eq!(
store.data().imports.f2_arg,
42,
"f2 should have been called with 42",
);
assert_eq!(store.data().imports.f3_a, 0);
assert_eq!(store.data().imports.f3_b, u32::MAX);
assert!(
store.data().imports.f4_called,
"the top-level JS imported and called `f4`",
);
// assert!(
// store.data().imports.f5_called,
// "the top-level JS imported and called `f5`"
// );
// assert_eq!(store.data().imports.f6_a, 100);
// assert_eq!(store.data().imports.f6_b, 200);
// assert_eq!(store.data().imports.f6_c, 300);
// Test that the export instance behaves as we expect it to.
exports
.f1(&mut store)
.context("calling the `f1` export should succeed")?;
exports
.f2(&mut store, 42)
.context("calling the `f2` export should succeed")?;
exports
.f3(&mut store, 0, u32::MAX)
.context("calling the `f3` export should succeed")?;
let a = exports
.f4(&mut store)
.context("calling the `f4` export should succeed")?;
assert_eq!(a, 1337);
// let (a, b) = exports
// .f5(&mut store)
// .context("calling the `f5` export should succeed")?;
// assert_eq!(a, 1);
// assert_eq!(b, 2);
// let (a, b, c) = exports
// .f6(&mut store, 100, 200, 300)
// .context("calling the `f6` export should succeed")?;
// assert_eq!(a, 101);
// assert_eq!(b, 201);
// assert_eq!(c, 301);
Ok(())
}

View File

@@ -0,0 +1,9 @@
f1: func()
f2: func(a: u32)
f3: func(a: u32, b: u32)
f4: func() -> u32
// TODO: should re-enable when re-implemented
//f5: func() -> tuple<u32, u32>
//
//f6: func(a: u32, b: u32, c: u32) -> tuple<u32, u32, u32>

View File

@@ -0,0 +1,83 @@
import * as imports from "imports";
function assert(condition, message) {
if (!condition) {
throw new Error(message);
}
}
function assertEq(a, b) {
assert(a == b, `assertEq failed: ${a} != ${b}`);
}
export function test_imports() {
// const { f1, f2, f3, f4, f5, f6 } = imports;
const { f1, f2, f3, f4 } = imports;
//
// Testing arguments.
//
f1();
f2(42);
// Min and max `u32`.
f3(0, 4294967295);
//
// Testing returns.
//
{
const a = f4();
assertEq(a, 1337);
}
// {
// const [a, b] = f5();
// assertEq(a, 1);
// assertEq(b, 2);
// }
// {
// const [a, b, c] = f6(100, 200, 300);
// assertEq(a, 101);
// assertEq(b, 201);
// assertEq(c, 301);
// }
}
//
// Testing arguments.
//
export function f1() {}
export function f2(x) {
assertEq(x, 42);
}
export function f3(a, b) {
assertEq(a, 0);
assertEq(b, 4294967295);
}
//
// Testing returns.
//
export function f4() {
return 1337;
}
export function f5() {
return [1, 2];
}
export function f6(a, b, c) {
assertEq(a, 100);
assertEq(b, 200);
assertEq(c, 300);
return [a + 1, b + 1, c + 1];
}

View File

@@ -0,0 +1,7 @@
test-imports: func()
f1: func(l: list<u32>)
f2: func() -> list<u32>
// TODO: should re-enable when re-implemented
// f3: func(a: list<u32>, b: list<u32>) -> tuple<list<u32>, list<u32>>
f4: func(l: list<list<u32>>) -> list<list<u32>>

View File

@@ -0,0 +1,88 @@
use anyhow::Context;
use wit_bindgen_wasmtime::Le;
wit_bindgen_wasmtime::export!("../../tests/runtime/smw_lists/imports.wit");
#[derive(Default)]
pub struct Host {
pub f1_l: Vec<u32>,
pub f2_called: bool,
// pub f3_a: Vec<u32>,
// pub f3_b: Vec<u32>,
pub f4_l: Vec<Vec<u32>>,
}
impl imports::Imports for Host {
fn f1(&mut self, l: &[Le<u32>]) {
self.f1_l = l.iter().map(|le| le.get()).collect();
}
fn f2(&mut self) -> Vec<u32> {
self.f2_called = true;
vec![1, 2, 3]
}
// fn f3(&mut self, a: &[Le<u32>], b: &[Le<u32>]) -> (Vec<u32>, Vec<u32>) {
// self.f3_a = a.iter().map(|le| le.get()).collect();
// self.f3_b = b.iter().map(|le| le.get()).collect();
// (vec![], vec![1, 2, 3])
// }
fn f4(&mut self, l: Vec<&[Le<u32>]>) -> Vec<Vec<u32>> {
self.f4_l = l
.into_iter()
.map(|xs| xs.iter().map(|le| le.get()).collect())
.collect();
vec![vec![], vec![4], vec![5, 6]]
}
}
wit_bindgen_wasmtime::import!("../../tests/runtime/smw_lists/exports.wit");
fn run(wasm: &str) -> anyhow::Result<()> {
let (exports, mut store) = crate::instantiate_smw(
wasm,
|linker| imports::add_to_linker(linker, |cx| -> &mut Host { &mut cx.imports }),
|store, module, linker| {
exports::Exports::instantiate(store, module, linker, |cx| &mut cx.exports)
},
)?;
// Test that the import instance called the functions we made available with
// the expected arguments.
exports.test_imports(&mut store)?;
assert_eq!(store.data().imports.f1_l, vec![1, 2, 3]);
assert!(store.data().imports.f2_called);
// assert_eq!(store.data().imports.f3_a, vec![]);
// assert_eq!(store.data().imports.f3_b, vec![1, 2, 3]);
assert_eq!(store.data().imports.f4_l, vec![vec![], vec![1], vec![2, 3]]);
// Test that the export instance behaves as we expect it to.
exports
.f1(&mut store, &[1, 2, 3])
.context("calling the `f1` export should succeed")?;
let l = exports
.f2(&mut store)
.context("calling the `f2` export should succeed")?;
assert_eq!(l, vec![1, 2, 3]);
// let (a, b) = exports
// .f3(&mut store, &[], &[1, 2, 3])
// .context("calling the `f3` export should succeed")?;
// assert_eq!(a, vec![]);
// assert_eq!(b, vec![1, 2, 3]);
let l = exports
.f4(&mut store, &[&[], &[1], &[2, 3]])
.context("calling the `f4` export should succeed")?;
assert_eq!(l, vec![vec![], vec![4], vec![5, 6]]);
Ok(())
}

View File

@@ -0,0 +1,5 @@
f1: func(l: list<u32>)
f2: func() -> list<u32>
// TODO: should re-enable when re-implemented
// f3: func(a: list<u32>, b: list<u32>) -> tuple<list<u32>, list<u32>>
f4: func(l: list<list<u32>>) -> list<list<u32>>

View File

@@ -0,0 +1,77 @@
import * as imports from "imports";
function assert(condition, message) {
if (!condition) {
throw new Error(message);
}
}
function assertEq(a, b) {
assert(a == b, `assertEq failed: ${a} != ${b}`);
}
export function test_imports() {
// const { f1, f2, f3, f4 } = imports;
const { f1, f2, f4 } = imports;
f1([1, 2, 3]);
const l = f2();
assertEq(l.length, 3);
assertEq(l[0], 1);
assertEq(l[1], 2);
assertEq(l[2], 3);
// const [a, b] = f3([], [1, 2, 3]);
// assertEq(a.length, 0);
// assertEq(b.length, 3);
// assertEq(b[0], 1);
// assertEq(b[1], 2);
// assertEq(b[2], 3);
const l2 = f4([[], [1], [2, 3]]);
assertEq(l2.length, 3);
assertEq(l2[0].length, 0);
assertEq(l2[1].length, 1);
assertEq(l2[1][0], 4);
assertEq(l2[2].length, 2);
assertEq(l2[2][0], 5);
assertEq(l2[2][1], 6);
}
export function f1(l) {
assertEq(l.length, 3);
assertEq(l[0], 1);
assertEq(l[1], 2);
assertEq(l[2], 3);
}
export function f2() {
return [1, 2, 3];
}
export function f3(a, b) {
assertEq(a.length, 0);
assertEq(b.length, 3);
assertEq(b[0], 1);
assertEq(b[1], 2);
assertEq(b[2], 3);
return [
[],
[1, 2, 3]
];
}
export function f4(l) {
assertEq(l.length, 3);
assertEq(l[0].length, 0);
assertEq(l[1].length, 1);
assertEq(l[1][0], 1);
assertEq(l[2].length, 2);
assertEq(l[2][0], 2);
assertEq(l[2][1], 3);
return [
[],
[4],
[5, 6]
];
}

View File

@@ -0,0 +1,7 @@
test-imports: func()
f1: func(s: string)
f2: func() -> string
// TODO: should re-enable when fixed
//f3: func(a: string, b:string, c: string) -> tuple<string, string, string>

View File

@@ -0,0 +1,75 @@
use anyhow::Context;
wit_bindgen_wasmtime::export!("../../tests/runtime/smw_strings/imports.wit");
#[derive(Default)]
pub struct Host {
pub f1_s: String,
pub f2_called: bool,
// pub f3_a: String,
// pub f3_b: String,
// pub f3_c: String,
}
impl imports::Imports for Host {
fn f1(&mut self, s: &str) {
self.f1_s = s.to_string();
}
fn f2(&mut self) -> String {
self.f2_called = true;
"36 chambers".into()
}
// fn f3(&mut self, a: &str, b: &str, c: &str) -> (String, String, String) {
// self.f3_a = a.into();
// self.f3_b = b.into();
// self.f3_c = c.into();
// (a.into(), b.into(), c.into())
// }
}
wit_bindgen_wasmtime::import!("../../tests/runtime/smw_strings/exports.wit");
fn run(wasm: &str) -> anyhow::Result<()> {
let (exports, mut store) = crate::instantiate_smw(
wasm,
|linker| imports::add_to_linker(linker, |cx| -> &mut Host { &mut cx.imports }),
|store, module, linker| {
exports::Exports::instantiate(store, module, linker, |cx| &mut cx.exports)
},
)?;
// Test that the import instance called the functions we made available with
// the expected arguments.
exports.test_imports(&mut store)?;
assert_eq!(store.data().imports.f1_s, "Hello, WIT!");
assert!(store.data().imports.f2_called, "JS should have called `f2`");
// assert_eq!(store.data().imports.f3_a, "");
// assert_eq!(store.data().imports.f3_b, "🚀");
// assert_eq!(store.data().imports.f3_c, "hello");
// Test that the export instance behaves as we expect it to.
exports
.f1(&mut store, "Hello, WIT!")
.context("calling the `f1` export should succeed")?;
let s = exports
.f2(&mut store)
.context("calling the `f2` export should succeed")?;
assert_eq!(s, "36 chambers");
// let (a, b, c) = exports
// .f3(&mut store, "", "🚀", "hello")
// .context("calling the `f3` export should succeed")?;
// assert_eq!(a, "");
// assert_eq!(b, "🚀");
// assert_eq!(c, "hello");
Ok(())
}

View File

@@ -0,0 +1,4 @@
f1: func(s: string)
f2: func() -> string
// TODO: should re-enable when fixed
//f3: func(a: string, b:string, c: string) -> tuple<string, string, string>

View File

@@ -0,0 +1,40 @@
import * as imports from "imports";
function assert(condition, message) {
if (!condition) {
throw new Error(message);
}
}
function assertEq(a, b) {
assert(a == b, `assertEq failed: ${a} != ${b}`);
}
export function test_imports() {
const { f1, f2 } = imports;
// const { f1, f2, f3 } = imports;
f1("Hello, WIT!");
const s = f2();
assertEq(s, "36 chambers");
// const [a, b, c] = f3("", "🚀", "hello");
// assertEq(a, "");
// assertEq(b, "🚀");
// assertEq(c, "hello");
}
export function f1(s) {
assertEq(s, "Hello, WIT!");
}
export function f2() {
return "36 chambers";
}
export function f3(a, b, c) {
assertEq(a, "");
assertEq(b, "🚀");
assertEq(c, "hello");
return [a, b, c];
}

View File

@@ -0,0 +1,59 @@
test-imports: func()
/// A union of all of the integral types
union all-integers {
/// Bool is equivalent to a 1 bit integer
/// and is treated that way in some languages
bool,
u8, u16, u32, u64,
s8, s16, s32, s64
}
union all-floats {
float32, float64
}
union all-text {
char, string
}
// Returns the same case as the input but with 1 added
add-one-integer: func(num: all-integers) -> all-integers
// Returns the same case as the input but with 1 added
add-one-float: func(num: all-floats) -> all-floats
// Returns the same case as the input but with the first character replaced
replace-first-char: func(text: all-text, letter: char) -> all-text
// Returns the index of the case provided
identify-integer: func(num: all-integers) -> u8
// Returns the index of the case provided
identify-float: func(num: all-floats) -> u8
// Returns the index of the case provided
identify-text: func(text: all-text) -> u8
union duplicated-s32 {
/// The first s32
s32,
/// The second s32
s32,
/// The third s32
s32
}
// Returns the same case as the input but with 1 added
add-one-duplicated: func(num: duplicated-s32) -> duplicated-s32
// Returns the index of the case provided
identify-duplicated: func(num: duplicated-s32) -> u8
/// A type containing numeric types that are distinct in most languages
union distinguishable-num {
/// A Floating Point Number
float64,
/// A Signed Integer
s64
}
// Returns the same case as the input but with 1 added
add-one-distinguishable-num: func(num: distinguishable-num) -> distinguishable-num
// Returns the index of the case provided
identify-distinguishable-num: func(num: distinguishable-num) -> u8

View File

@@ -0,0 +1,237 @@
from exports.bindings import Exports
from imports.bindings import add_imports_to_linker, Imports
from typing import Union
import exports.bindings as e
import imports.bindings as i
import sys
import wasmtime
class MyImports:
# Simple uses of unions whose inner values all have the same Python representation
def add_one_integer(self, num: i.AllIntegers) -> i.AllIntegers:
# Bool
if isinstance(num, i.AllIntegers0):
assert num.value in (True, False)
return i.AllIntegers0(not num.value)
# The unsigned numbers
elif isinstance(num, i.AllIntegers1):
lower_limit = 0
upper_limit = 2**8
assert lower_limit <= num.value < upper_limit
return i.AllIntegers1(num.value + 1 % upper_limit)
elif isinstance(num, i.AllIntegers2):
lower_limit = 0
upper_limit = 2**16
assert lower_limit <= num.value < upper_limit
return i.AllIntegers2(num.value + 1 % upper_limit)
elif isinstance(num, i.AllIntegers3):
lower_limit = 0
upper_limit = 2**32
assert lower_limit <= num.value < upper_limit
return i.AllIntegers3(num.value + 1 % upper_limit)
elif isinstance(num, i.AllIntegers4):
lower_limit = 0
upper_limit = 2**64
assert lower_limit <= num.value < upper_limit
return i.AllIntegers4(num.value + 1 % upper_limit)
# The signed numbers
elif isinstance(num, i.AllIntegers5):
lower_limit = -2**7
upper_limit = 2**7
assert lower_limit <= num.value < upper_limit
return i.AllIntegers5(num.value + 1 % upper_limit)
elif isinstance(num, i.AllIntegers6):
lower_limit = -2**15
upper_limit = 2**15
assert lower_limit <= num.value < upper_limit
return i.AllIntegers6(num.value + 1 % upper_limit)
elif isinstance(num, i.AllIntegers7):
lower_limit = -2**31
upper_limit = 2**31
assert lower_limit <= num.value < upper_limit
return i.AllIntegers7(num.value + 1 % upper_limit)
elif isinstance(num, i.AllIntegers8):
lower_limit = -2**63
upper_limit = 2**63
assert lower_limit <= num.value < upper_limit
return i.AllIntegers8(num.value + 1 % upper_limit)
else:
raise ValueError("Invalid input value!")
def add_one_float(self, num: i.AllFloats) -> i.AllFloats:
if isinstance(num, i.AllFloats0):
return i.AllFloats0(num.value + 1)
if isinstance(num, i.AllFloats1):
return i.AllFloats1(num.value + 1)
else:
raise ValueError("Invalid input value!")
def replace_first_char(self, text: i.AllText, letter: str) -> i.AllText:
if isinstance(text, i.AllText0):
return i.AllText0(letter)
if isinstance(text, i.AllFloats1):
return i.AllText1(letter + text.value[1:])
else:
raise ValueError("Invalid input value!")
# Identify each case of unions whose inner values all have the same Python representation
def identify_integer(self, num: i.AllIntegers) -> int:
# Bool
if isinstance(num, i.AllIntegers0):
return 0
# The unsigned numbers
elif isinstance(num, i.AllIntegers1):
return 1
elif isinstance(num, i.AllIntegers2):
return 2
elif isinstance(num, i.AllIntegers3):
return 3
elif isinstance(num, i.AllIntegers4):
return 4
# The signed numbers
elif isinstance(num, i.AllIntegers5):
return 5
elif isinstance(num, i.AllIntegers6):
return 6
elif isinstance(num, i.AllIntegers7):
return 7
elif isinstance(num, i.AllIntegers8):
return 8
else:
raise ValueError("Invalid input value!")
def identify_float(self, num: i.AllFloats) -> int:
if isinstance(num, i.AllFloats0):
return 0
if isinstance(num, i.AllFloats1):
return 1
else:
raise ValueError("Invalid input value!")
def identify_text(self, text: i.AllText) -> int:
if isinstance(text, i.AllText0):
return 0
if isinstance(text, i.AllFloats1):
return 1
else:
raise ValueError("Invalid input value!")
# A simple use of a union which contains multiple entries of the same type
def add_one_duplicated(self, num: i.DuplicatedS32) -> i.DuplicatedS32:
if isinstance(num, i.DuplicatedS320):
return i.DuplicatedS320(num.value + 1)
if isinstance(num, i.DuplicatedS321):
return i.DuplicatedS321(num.value + 1)
if isinstance(num, i.DuplicatedS322):
return i.DuplicatedS322(num.value + 1)
else:
raise ValueError("Invalid input value!")
# Identify each case of unions which contains multiple entries of the same type
def identify_duplicated(self, num: i.DuplicatedS32) -> int:
if isinstance(num, i.DuplicatedS320):
return 0
if isinstance(num, i.DuplicatedS321):
return 1
if isinstance(num, i.DuplicatedS322):
return 2
else:
raise ValueError("Invalid input value!")
# A simple use of a union whose cases have distinct Python representations
def add_one_distinguishable_num(self, num: Union[float, int]) -> Union[float, int]:
return num + 1
# Identify each case of unions whose cases have distinct Python representations
def identify_distinguishable_num(self, num: i.DistinguishableNum) -> int:
if isinstance(num, float):
return 0
elif isinstance(num, int):
return 1
else:
raise ValueError("Invalid input value!")
def run(wasm_file: str) -> None:
store = wasmtime.Store()
module = wasmtime.Module.from_file(store.engine, wasm_file)
linker = wasmtime.Linker(store.engine)
linker.define_wasi()
wasi = wasmtime.WasiConfig()
wasi.inherit_stdout()
wasi.inherit_stderr()
store.set_wasi(wasi)
imports = MyImports()
add_imports_to_linker(linker, store, imports)
wasm = Exports(store, linker, module)
# wasm.test_imports(store)
# All-Integers
# Booleans
assert wasm.add_one_integer(store, e.AllIntegers0(False)) == e.AllIntegers0(True)
assert wasm.add_one_integer(store, e.AllIntegers0(True)) == e.AllIntegers0(False)
# Unsigned integers
assert wasm.add_one_integer(store, e.AllIntegers1(0)) == e.AllIntegers1(1)
assert wasm.add_one_integer(store, e.AllIntegers1(2**8-1)) == e.AllIntegers1(0)
assert wasm.add_one_integer(store, e.AllIntegers2(0)) == e.AllIntegers2(1)
assert wasm.add_one_integer(store, e.AllIntegers2(2**16-1)) == e.AllIntegers2(0)
assert wasm.add_one_integer(store, e.AllIntegers3(0)) == e.AllIntegers3(1)
assert wasm.add_one_integer(store, e.AllIntegers3(2**32-1)) == e.AllIntegers3(0)
assert wasm.add_one_integer(store, e.AllIntegers4(0)) == e.AllIntegers4(1)
assert wasm.add_one_integer(store, e.AllIntegers4(2**64-1)) == e.AllIntegers4(0)
# Signed integers
assert wasm.add_one_integer(store, e.AllIntegers5(0)) == e.AllIntegers5(1)
assert wasm.add_one_integer(store, e.AllIntegers5(2**7-1)) == e.AllIntegers5(-2**7)
assert wasm.add_one_integer(store, e.AllIntegers6(0)) == e.AllIntegers6(1)
assert wasm.add_one_integer(store, e.AllIntegers6(2**15-1)) == e.AllIntegers6(-2**15)
assert wasm.add_one_integer(store, e.AllIntegers7(0)) == e.AllIntegers7(1)
assert wasm.add_one_integer(store, e.AllIntegers7(2**31-1)) == e.AllIntegers7(-2**31)
assert wasm.add_one_integer(store, e.AllIntegers8(0)) == e.AllIntegers8(1)
assert wasm.add_one_integer(store, e.AllIntegers8(2**63-1)) == e.AllIntegers8(-2**63)
# All-Floats
assert wasm.add_one_float(store, e.AllFloats0(0.0)) == e.AllFloats0(1.0)
assert wasm.add_one_float(store, e.AllFloats1(0.0)) == e.AllFloats1(1.0)
# All-Text
assert wasm.replace_first_char(store, e.AllText0('a'), 'z') == e.AllText0('z')
assert wasm.replace_first_char(store, e.AllText1('abc'), 'z') == e.AllText1('zbc')
# All-Integers
assert wasm.identify_integer(store, e.AllIntegers0(True)) == 0
assert wasm.identify_integer(store, e.AllIntegers1(0)) == 1
assert wasm.identify_integer(store, e.AllIntegers2(0)) == 2
assert wasm.identify_integer(store, e.AllIntegers3(0)) == 3
assert wasm.identify_integer(store, e.AllIntegers4(0)) == 4
assert wasm.identify_integer(store, e.AllIntegers5(0)) == 5
assert wasm.identify_integer(store, e.AllIntegers6(0)) == 6
assert wasm.identify_integer(store, e.AllIntegers7(0)) == 7
assert wasm.identify_integer(store, e.AllIntegers8(0)) == 8
# All-Floats
assert wasm.identify_float(store, e.AllFloats0(0.0)) == 0
assert wasm.identify_float(store, e.AllFloats1(0.0)) == 1
# All-Text
assert wasm.identify_text(store, e.AllText0('a')) == 0
assert wasm.identify_text(store, e.AllText1('abc')) == 1
# Duplicated
assert wasm.add_one_duplicated(store, e.DuplicatedS320(0)) == e.DuplicatedS320(1)
assert wasm.add_one_duplicated(store, e.DuplicatedS321(1)) == e.DuplicatedS321(2)
assert wasm.add_one_duplicated(store, e.DuplicatedS322(2)) == e.DuplicatedS322(3)
assert wasm.identify_duplicated(store, e.DuplicatedS320(0)) == 0
assert wasm.identify_duplicated(store, e.DuplicatedS321(0)) == 1
assert wasm.identify_duplicated(store, e.DuplicatedS322(0)) == 2
# Distinguishable
assert wasm.add_one_distinguishable_num(store, 0.0) == 1.0
assert wasm.add_one_distinguishable_num(store, 0) == 1
assert wasm.identify_distinguishable_num(store, 0.0) == 0
assert wasm.identify_distinguishable_num(store, 1) == 1
if __name__ == '__main__':
run(sys.argv[1])

View File

@@ -0,0 +1,57 @@
/// A union of all of the integral types
union all-integers {
/// Bool is equivalent to a 1 bit integer
/// and is treated that way in some languages
bool,
u8, u16, u32, u64,
s8, s16, s32, s64
}
union all-floats {
float32, float64
}
union all-text {
char, string
}
// Returns the same case as the input but with 1 added
add-one-integer: func(num: all-integers) -> all-integers
// Returns the same case as the input but with 1 added
add-one-float: func(num: all-floats) -> all-floats
// Returns the same case as the input but with the first character replaced
replace-first-char: func(text: all-text, letter: char) -> all-text
// Returns the index of the case provided
identify-integer: func(num: all-integers) -> u8
// Returns the index of the case provided
identify-float: func(num: all-floats) -> u8
// Returns the index of the case provided
identify-text: func(text: all-text) -> u8
union duplicated-s32 {
/// The first s32
s32,
/// The second s32
s32,
/// The third s32
s32
}
// Returns the same case as the input but with 1 added
add-one-duplicated: func(num: duplicated-s32) -> duplicated-s32
// Returns the index of the case provided
identify-duplicated: func(num: duplicated-s32) -> u8
/// A type containing numeric types that are distinct in most languages
union distinguishable-num {
/// A Floating Point Number
float64,
/// A Signed Integer
s64
}
// Returns the same case as the input but with 1 added
add-one-distinguishable-num: func(num: distinguishable-num) -> distinguishable-num
// Returns the index of the case provided
identify-distinguishable-num: func(num: distinguishable-num) -> u8

View File

@@ -0,0 +1,171 @@
wit_bindgen_rust::import!("../../tests/runtime/unions/imports.wit");
wit_bindgen_rust::export!("../../tests/runtime/unions/exports.wit");
use exports::*;
struct Exports;
impl exports::Exports for Exports {
fn test_imports() {
use imports::*;
// All-Integers
// Booleans
assert!(matches!(add_one_integer(AllIntegers::Bool(false)), AllIntegers::Bool(true)));
assert!(matches!(add_one_integer(AllIntegers::Bool(true)), AllIntegers::Bool(false)));
// Unsigned integers
assert!(matches!(add_one_integer(AllIntegers::U8(0)), AllIntegers::U8(1)));
assert!(matches!(add_one_integer(AllIntegers::U8(u8::MAX)), AllIntegers::U8(0)));
assert!(matches!(add_one_integer(AllIntegers::U16(0)), AllIntegers::U16(1)));
assert!(matches!(add_one_integer(AllIntegers::U16(u16::MAX)), AllIntegers::U16(0)));
assert!(matches!(add_one_integer(AllIntegers::U32(0)), AllIntegers::U32(1)));
assert!(matches!(add_one_integer(AllIntegers::U32(u32::MAX)), AllIntegers::U32(0)));
assert!(matches!(add_one_integer(AllIntegers::U64(0)), AllIntegers::U64(1)));
assert!(matches!(add_one_integer(AllIntegers::U64(u64::MAX)), AllIntegers::U64(0)));
// Signed integers
assert!(matches!(add_one_integer(AllIntegers::I8(0)), AllIntegers::I8(1)));
assert!(matches!(add_one_integer(AllIntegers::I8(i8::MAX)), AllIntegers::I8(i8::MIN)));
assert!(matches!(add_one_integer(AllIntegers::I16(0)), AllIntegers::I16(1)));
assert!(matches!(add_one_integer(AllIntegers::I16(i16::MAX)), AllIntegers::I16(i16::MIN)));
assert!(matches!(add_one_integer(AllIntegers::I32(0)), AllIntegers::I32(1)));
assert!(matches!(add_one_integer(AllIntegers::I32(i32::MAX)), AllIntegers::I32(i32::MIN)));
assert!(matches!(add_one_integer(AllIntegers::I64(0)), AllIntegers::I64(1)));
assert!(matches!(add_one_integer(AllIntegers::I64(i64::MAX)), AllIntegers::I64(i64::MIN)));
// All-Floats
assert!(matches!(add_one_float(AllFloats::F32(0.0)), AllFloats::F32(1.0)));
assert!(matches!(add_one_float(AllFloats::F64(0.0)), AllFloats::F64(1.0)));
// All-Text
assert!(matches!(replace_first_char(AllTextParam::Char('a'), 'z'), AllTextResult::Char('z')));
let rhs = "zbc".to_string();
assert!(matches!(replace_first_char(AllTextParam::String("abc"), 'z'), AllTextResult::String(rhs)));
// All-Integers
assert!(matches!(identify_integer(AllIntegers::Bool(true)), 0));
assert!(matches!(identify_integer(AllIntegers::U8(0)), 1));
assert!(matches!(identify_integer(AllIntegers::U16(0)), 2));
assert!(matches!(identify_integer(AllIntegers::U32(0)), 3));
assert!(matches!(identify_integer(AllIntegers::U64(0)), 4));
assert!(matches!(identify_integer(AllIntegers::I8(0)), 5));
assert!(matches!(identify_integer(AllIntegers::I16(0)), 6));
assert!(matches!(identify_integer(AllIntegers::I32(0)), 7));
assert!(matches!(identify_integer(AllIntegers::I64(0)), 8));
// All-Floats
assert!(matches!(identify_float(AllFloats::F32(0.0)), 0));
assert!(matches!(identify_float(AllFloats::F64(0.0)), 1));
// All-Text
assert!(matches!(identify_text(AllTextParam::Char('a')), 0));
assert!(matches!(identify_text(AllTextParam::String("abc")), 1));
// Duplicated
assert!(matches!(add_one_duplicated(DuplicatedS32::I320(0)), DuplicatedS32::I320(1)));
assert!(matches!(add_one_duplicated(DuplicatedS32::I321(1)), DuplicatedS32::I321(2)));
assert!(matches!(add_one_duplicated(DuplicatedS32::I322(2)), DuplicatedS32::I322(3)));
assert!(matches!(identify_duplicated(DuplicatedS32::I320(0)), 0));
assert!(matches!(identify_duplicated(DuplicatedS32::I321(0)), 1));
assert!(matches!(identify_duplicated(DuplicatedS32::I321(0)), 2));
// Distinguishable
assert!(matches!(add_one_distinguishable_num(DistinguishableNum::F64(0.0)), DistinguishableNum::F64(1.0)));
assert!(matches!(add_one_distinguishable_num(DistinguishableNum::I64(0)), DistinguishableNum::I64(1)));
assert!(matches!(identify_distinguishable_num(DistinguishableNum::F64(0.0)), 0));
assert!(matches!(identify_distinguishable_num(DistinguishableNum::I64(1)), 1));
}
fn add_one_integer(num: AllIntegers) -> AllIntegers {
match num {
// Boolean
AllIntegers::Bool(b) => AllIntegers::Bool(!b),
// Unsigneed Integers
AllIntegers::U8(n) => AllIntegers::U8(n.wrapping_add(1)),
AllIntegers::U16(n) => AllIntegers::U16(n.wrapping_add(1)),
AllIntegers::U32(n) => AllIntegers::U32(n.wrapping_add(1)),
AllIntegers::U64(n) => AllIntegers::U64(n.wrapping_add(1)),
// Signed Integers
AllIntegers::I8(n) => AllIntegers::I8(n.wrapping_add(1)),
AllIntegers::I16(n) => AllIntegers::I16(n.wrapping_add(1)),
AllIntegers::I32(n) => AllIntegers::I32(n.wrapping_add(1)),
AllIntegers::I64(n) => AllIntegers::I64(n.wrapping_add(1)),
}
}
fn add_one_float(num: AllFloats) -> AllFloats {
match num {
AllFloats::F32(n) => AllFloats::F32(n + 1.0),
AllFloats::F64(n) => AllFloats::F64(n + 1.0),
}
}
fn replace_first_char(text: AllText, letter: char) -> AllText {
match text {
AllText::Char(c) => AllText::Char(letter),
AllText::String(s) => AllText::String(format!("{}{}", letter, &s[1..]))
}
}
fn identify_integer(num: AllIntegers) -> u8 {
match num {
// Boolean
AllIntegers::Bool(_b) => 0,
// Unsigneed Integers
AllIntegers::U8(_n) => 1,
AllIntegers::U16(_n) => 2,
AllIntegers::U32(_n) => 3,
AllIntegers::U64(_n) => 4,
// Signed Integers
AllIntegers::I8(_n) => 5,
AllIntegers::I16(_n) => 6,
AllIntegers::I32(_n) => 7,
AllIntegers::I64(_n) => 8,
}
}
fn identify_float(num: AllFloats) -> u8 {
match num {
AllFloats::F32(_n) => 0,
AllFloats::F64(_n) => 1,
}
}
fn identify_text(text: AllText) -> u8 {
match text {
AllText::Char(_c) => 0,
AllText::String(_s) => 1
}
}
fn add_one_duplicated(num: DuplicatedS32) -> DuplicatedS32 {
match num {
DuplicatedS32::I320(n) => DuplicatedS32::I320(n.wrapping_add(1)),
DuplicatedS32::I321(n) => DuplicatedS32::I321(n.wrapping_add(1)),
DuplicatedS32::I322(n) => DuplicatedS32::I322(n.wrapping_add(1)),
}
}
fn identify_duplicated(num: DuplicatedS32) -> u8 {
match num {
DuplicatedS32::I320(_n) => 0,
DuplicatedS32::I321(_n) => 1,
DuplicatedS32::I322(_n) => 2,
}
}
fn add_one_distinguishable_num(num: DistinguishableNum) -> DistinguishableNum {
match num {
DistinguishableNum::F64(n) => DistinguishableNum::F64(n + 1.0),
DistinguishableNum::I64(n) => DistinguishableNum::I64(n.wrapping_add(1)),
}
}
fn identify_distinguishable_num(num: DistinguishableNum) -> u8 {
match num {
DistinguishableNum::F64(_n) => 0,
DistinguishableNum::I64(_n) => 1,
}
}
}

View File

@@ -0,0 +1,30 @@
test-imports: func()
roundtrip-option: func(a: option<float32>) -> option<u8>
roundtrip-result: func(a: expected<u32, float32>) -> expected<float64, u8>
enum e1 { a, b }
roundtrip-enum: func(a: e1) -> e1
invert-bool: func(a: bool) -> bool
variant c1 { a(s32), b(s64) }
variant c2 { a(s32), b(float32) }
variant c3 { a(s32), b(float64) }
variant c4 { a(s64), b(float32) }
variant c5 { a(s64), b(float64) }
variant c6 { a(float32), b(float64) }
type casts = tuple<c1, c2, c3, c4, c5, c6>
variant-casts: func(a: casts) -> casts
variant z1 { a(s32), b }
variant z2 { a(s64), b }
variant z3 { a(float32), b }
variant z4 { a(float64), b }
type zeros = tuple<z1, z2, z3, z4>
variant-zeros: func(a: zeros) -> zeros
type option-typedef = option<u32>
type bool-typedef = bool
type result-typedef = expected<u32, unit>
variant-typedefs: func(a: option-typedef, b: bool-typedef, c: result-typedef)

View File

@@ -0,0 +1,114 @@
from exports.bindings import Exports
from imports.bindings import add_imports_to_linker, Imports
from typing import Optional, Tuple
import exports.bindings as e
import imports.bindings as i
import sys
import wasmtime
class MyImports:
def roundtrip_option(self, a: Optional[float]) -> Optional[int]:
if a:
return int(a)
return None
def roundtrip_result(self, a: i.Expected[int, float]) -> i.Expected[float, int]:
if isinstance(a, i.Ok):
return i.Ok(float(a.value))
return i.Err(int(a.value))
def roundtrip_enum(self, a: i.E1) -> i.E1:
return a
def invert_bool(self, a: bool) -> bool:
return not a
def variant_casts(self, a: i.Casts) -> i.Casts:
return a
def variant_zeros(self, a: i.Zeros) -> i.Zeros:
return a
def variant_typedefs(self, a: i.OptionTypedef, b: i.BoolTypedef, c: i.ResultTypedef) -> None:
pass
def variant_enums(self, a: bool, b: i.Expected[None, None], c: i.MyErrno) -> Tuple[bool, i.Expected[None, None], i.MyErrno]:
assert(a)
assert(isinstance(b, i.Ok))
assert(c == i.MyErrno.SUCCESS)
return (False, i.Err(None), i.MyErrno.A)
def run(wasm_file: str) -> None:
store = wasmtime.Store()
module = wasmtime.Module.from_file(store.engine, wasm_file)
linker = wasmtime.Linker(store.engine)
linker.define_wasi()
wasi = wasmtime.WasiConfig()
wasi.inherit_stdout()
wasi.inherit_stderr()
store.set_wasi(wasi)
imports = MyImports()
add_imports_to_linker(linker, store, imports)
wasm = Exports(store, linker, module)
wasm.test_imports(store)
assert(wasm.roundtrip_option(store, 1.) == 1)
assert(wasm.roundtrip_option(store, None) == None)
assert(wasm.roundtrip_option(store, 2.) == 2)
assert(wasm.roundtrip_result(store, e.Ok(2)) == e.Ok(2))
assert(wasm.roundtrip_result(store, e.Ok(4)) == e.Ok(4))
assert(wasm.roundtrip_result(store, e.Err(5)) == e.Err(5))
assert(wasm.roundtrip_enum(store, e.E1.A) == e.E1.A)
assert(wasm.roundtrip_enum(store, e.E1.B) == e.E1.B)
assert(wasm.invert_bool(store, True) == False)
assert(wasm.invert_bool(store, False) == True)
a1, a2, a3, a4, a5, a6 = wasm.variant_casts(store, (
e.C1A(1),
e.C2A(2),
e.C3A(3),
e.C4A(4),
e.C5A(5),
e.C6A(6.),
))
assert(a1 == e.C1A(1))
assert(a2 == e.C2A(2))
assert(a3 == e.C3A(3))
assert(a4 == e.C4A(4))
assert(a5 == e.C5A(5))
assert(a6 == e.C6A(6))
b1, b2, b3, b4, b5, b6 = wasm.variant_casts(store, (
e.C1B(1),
e.C2B(2),
e.C3B(3),
e.C4B(4),
e.C5B(5),
e.C6B(6.),
))
assert(b1 == e.C1B(1))
assert(b2 == e.C2B(2))
assert(b3 == e.C3B(3))
assert(b4 == e.C4B(4))
assert(b5 == e.C5B(5))
assert(b6 == e.C6B(6))
z1, z2, z3, z4 = wasm.variant_zeros(store, (
e.Z1A(1),
e.Z2A(2),
e.Z3A(3.),
e.Z4A(4.),
))
assert(z1 == e.Z1A(1))
assert(z2 == e.Z2A(2))
assert(z3 == e.Z3A(3))
assert(z4 == e.Z4A(4))
wasm.variant_typedefs(store, None, False, e.Err(None))
if __name__ == '__main__':
run(sys.argv[1])

View File

@@ -0,0 +1,119 @@
use anyhow::Result;
wit_bindgen_wasmtime::export!("../../tests/runtime/variants/imports.wit");
use imports::*;
#[derive(Default)]
pub struct MyImports;
impl Imports for MyImports {
fn roundtrip_option(&mut self, a: Option<f32>) -> Option<u8> {
a.map(|x| x as u8)
}
fn roundtrip_result(&mut self, a: Result<u32, f32>) -> Result<f64, u8> {
match a {
Ok(a) => Ok(a.into()),
Err(b) => Err(b as u8),
}
}
fn roundtrip_enum(&mut self, a: E1) -> E1 {
assert_eq!(a, a);
a
}
fn invert_bool(&mut self, a: bool) -> bool {
!a
}
fn variant_casts(&mut self, a: Casts) -> Casts {
a
}
fn variant_zeros(&mut self, a: Zeros) -> Zeros {
a
}
fn variant_typedefs(&mut self, _: Option<u32>, _: bool, _: Result<u32, ()>) {}
fn variant_enums(
&mut self,
a: bool,
b: Result<(), ()>,
c: MyErrno,
) -> (bool, Result<(), ()>, MyErrno) {
assert_eq!(a, true);
assert_eq!(b, Ok(()));
assert_eq!(c, MyErrno::Success);
(false, Err(()), MyErrno::A)
}
}
wit_bindgen_wasmtime::import!("../../tests/runtime/variants/exports.wit");
fn run(wasm: &str) -> Result<()> {
use exports::*;
let (exports, mut store) = crate::instantiate(
wasm,
|linker| imports::add_to_linker(linker, |cx| -> &mut MyImports { &mut cx.imports }),
|store, module, linker| Exports::instantiate(store, module, linker, |cx| &mut cx.exports),
)?;
exports.test_imports(&mut store)?;
assert_eq!(exports.roundtrip_option(&mut store, Some(1.0))?, Some(1));
assert_eq!(exports.roundtrip_option(&mut store, None)?, None);
assert_eq!(exports.roundtrip_option(&mut store, Some(2.0))?, Some(2));
assert_eq!(exports.roundtrip_result(&mut store, Ok(2))?, Ok(2.0));
assert_eq!(exports.roundtrip_result(&mut store, Ok(4))?, Ok(4.0));
assert_eq!(exports.roundtrip_result(&mut store, Err(5.3))?, Err(5));
assert_eq!(exports.roundtrip_enum(&mut store, E1::A)?, E1::A);
assert_eq!(exports.roundtrip_enum(&mut store, E1::B)?, E1::B);
assert_eq!(exports.invert_bool(&mut store, true)?, false);
assert_eq!(exports.invert_bool(&mut store, false)?, true);
let (a1, a2, a3, a4, a5, a6) = exports.variant_casts(
&mut store,
(C1::A(1), C2::A(2), C3::A(3), C4::A(4), C5::A(5), C6::A(6.0)),
)?;
assert!(matches!(a1, C1::A(1)));
assert!(matches!(a2, C2::A(2)));
assert!(matches!(a3, C3::A(3)));
assert!(matches!(a4, C4::A(4)));
assert!(matches!(a5, C5::A(5)));
assert!(matches!(a6, C6::A(b) if b == 6.0));
let (a1, a2, a3, a4, a5, a6) = exports.variant_casts(
&mut store,
(
C1::B(1),
C2::B(2.0),
C3::B(3.0),
C4::B(4.0),
C5::B(5.0),
C6::B(6.0),
),
)?;
assert!(matches!(a1, C1::B(1)));
assert!(matches!(a2, C2::B(b) if b == 2.0));
assert!(matches!(a3, C3::B(b) if b == 3.0));
assert!(matches!(a4, C4::B(b) if b == 4.0));
assert!(matches!(a5, C5::B(b) if b == 5.0));
assert!(matches!(a6, C6::B(b) if b == 6.0));
let (a1, a2, a3, a4) =
exports.variant_zeros(&mut store, (Z1::A(1), Z2::A(2), Z3::A(3.0), Z4::A(4.0)))?;
assert!(matches!(a1, Z1::A(1)));
assert!(matches!(a2, Z2::A(2)));
assert!(matches!(a3, Z3::A(b) if b == 3.0));
assert!(matches!(a4, Z4::A(b) if b == 4.0));
exports.variant_typedefs(&mut store, None, false, Err(()))?;
Ok(())
}

View File

@@ -0,0 +1,108 @@
import { addImportsToImports, Imports, MyErrno } from "./imports.js";
import { Exports } from "./exports.js";
import * as exports from "./exports.js";
import { getWasm, addWasiToImports } from "./helpers.js";
// @ts-ignore
import * as assert from 'assert';
async function run() {
const importObj = {};
const imports: Imports = {
roundtripOption(x) { return x; },
roundtripResult(x) {
if (x.tag == 'ok') {
return { tag: 'ok', val: x.val };
} else {
return { tag: 'err', val: Math.round(x.val) };
}
},
roundtripEnum(x) { return x; },
invertBool(x) { return !x; },
variantCasts(x) { return x; },
variantZeros(x) { return x; },
variantTypedefs(x, y, z) {},
variantEnums(a, b, c) {
assert.deepStrictEqual(a, true);
assert.deepStrictEqual(b, { tag: 'ok', val: undefined });
assert.deepStrictEqual(c, "success");
return [
false,
{ tag: 'err', val: undefined },
"a",
];
},
};
let instance: WebAssembly.Instance;
addImportsToImports(importObj, imports, name => instance.exports[name]);
const wasi = addWasiToImports(importObj);
const wasm = new Exports();
await wasm.instantiate(getWasm(), importObj);
wasi.start(wasm.instance);
instance = wasm.instance;
wasm.testImports();
assert.deepStrictEqual(wasm.roundtripOption(1), 1);
assert.deepStrictEqual(wasm.roundtripOption(null), null);
assert.deepStrictEqual(wasm.roundtripOption(2), 2);
assert.deepStrictEqual(wasm.roundtripResult({ tag: 'ok', val: 2 }), { tag: 'ok', val: 2 });
assert.deepStrictEqual(wasm.roundtripResult({ tag: 'ok', val: 4 }), { tag: 'ok', val: 4 });
const f = Math.fround(5.2);
assert.deepStrictEqual(wasm.roundtripResult({ tag: 'err', val: f }), { tag: 'err', val: 5 });
assert.deepStrictEqual(wasm.roundtripEnum("a"), "a");
assert.deepStrictEqual(wasm.roundtripEnum("b"), "b");
assert.deepStrictEqual(wasm.invertBool(true), false);
assert.deepStrictEqual(wasm.invertBool(false), true);
{
const [a1, a2, a3, a4, a5, a6] = wasm.variantCasts([
{ tag: 'a', val: 1 },
{ tag: 'a', val: 2 },
{ tag: 'a', val: 3 },
{ tag: 'a', val: 4n },
{ tag: 'a', val: 5n },
{ tag: 'a', val: 6 },
]);
assert.deepStrictEqual(a1, { tag: 'a', val: 1 });
assert.deepStrictEqual(a2, { tag: 'a', val: 2 });
assert.deepStrictEqual(a3, { tag: 'a', val: 3 });
assert.deepStrictEqual(a4, { tag: 'a', val: 4n });
assert.deepStrictEqual(a5, { tag: 'a', val: 5n });
assert.deepStrictEqual(a6, { tag: 'a', val: 6 });
}
{
const [b1, b2, b3, b4, b5, b6] = wasm.variantCasts([
{ tag: 'b', val: 1n },
{ tag: 'b', val: 2 },
{ tag: 'b', val: 3 },
{ tag: 'b', val: 4 },
{ tag: 'b', val: 5 },
{ tag: 'b', val: 6 },
]);
assert.deepStrictEqual(b1, { tag: 'b', val: 1n });
assert.deepStrictEqual(b2, { tag: 'b', val: 2 });
assert.deepStrictEqual(b3, { tag: 'b', val: 3 });
assert.deepStrictEqual(b4, { tag: 'b', val: 4 });
assert.deepStrictEqual(b5, { tag: 'b', val: 5 });
assert.deepStrictEqual(b6, { tag: 'b', val: 6 });
}
{
const [a1, a2, a3, a4] = wasm.variantZeros([
{ tag: 'a', val: 1 },
{ tag: 'a', val: 2n },
{ tag: 'a', val: 3 },
{ tag: 'a', val: 4 },
]);
assert.deepStrictEqual(a1, { tag: 'a', val: 1 });
assert.deepStrictEqual(a2, { tag: 'a', val: 2n });
assert.deepStrictEqual(a3, { tag: 'a', val: 3 });
assert.deepStrictEqual(a4, { tag: 'a', val: 4 });
}
wasm.variantTypedefs(null, false, { tag: 'err', val: undefined });
}
await run()

View File

@@ -0,0 +1,31 @@
roundtrip-option: func(a: option<float32>) -> option<u8>
roundtrip-result: func(a: expected<u32, float32>) -> expected<float64, u8>
enum e1 { a, b }
roundtrip-enum: func(a: e1) -> e1
invert-bool: func(a: bool) -> bool
variant c1 { a(s32), b(s64) }
variant c2 { a(s32), b(float32) }
variant c3 { a(s32), b(float64) }
variant c4 { a(s64), b(float32) }
variant c5 { a(s64), b(float64) }
variant c6 { a(float32), b(float64) }
type casts = tuple<c1, c2, c3, c4, c5, c6>
variant-casts: func(a: casts) -> casts
variant z1 { a(s32), b }
variant z2 { a(s64), b }
variant z3 { a(float32), b }
variant z4 { a(float64), b }
type zeros = tuple<z1, z2, z3, z4>
variant-zeros: func(a: zeros) -> zeros
type option-typedef = option<u32>
type bool-typedef = bool
type result-typedef = expected<u32, unit>
variant-typedefs: func(a: option-typedef, b: bool-typedef, c: result-typedef)
enum my-errno { success, a, b }
variant-enums: func(a: bool, b: expected<unit, unit>, c: my-errno) -> tuple<bool, expected<unit, unit>, my-errno>

View File

@@ -0,0 +1,208 @@
#include <assert.h>
#include <imports.h>
#include <exports.h>
void exports_test_imports() {
{
imports_option_float32_t a;
uint8_t r;
a.is_some = true;
a.val = 1;
assert(imports_roundtrip_option(&a, &r) && r == 1);
assert(r == 1);
a.is_some = false;
assert(!imports_roundtrip_option(&a, &r));
a.is_some = true;
a.val = 2;
assert(imports_roundtrip_option(&a, &r) && r == 2);
}
{
imports_expected_u32_float32_t a;
imports_expected_float64_u8_t b;
a.is_err = false;
a.val.ok = 2;
imports_roundtrip_result(&a, &b);
assert(!b.is_err);
assert(b.val.ok == 2.0);
a.val.ok = 4;
imports_roundtrip_result(&a, &b);
assert(!b.is_err);
assert(b.val.ok == 4);
a.is_err = true;
a.val.err = 5.3;
imports_roundtrip_result(&a, &b);
assert(b.is_err);
assert(b.val.err == 5);
}
assert(imports_roundtrip_enum(IMPORTS_E1_A) == IMPORTS_E1_A);
assert(imports_roundtrip_enum(IMPORTS_E1_B) == IMPORTS_E1_B);
assert(imports_invert_bool(true) == false);
assert(imports_invert_bool(false) == true);
{
imports_casts_t c;
imports_c1_t r1;
imports_c2_t r2;
imports_c3_t r3;
imports_c4_t r4;
imports_c5_t r5;
imports_c6_t r6;
c.f0.tag = IMPORTS_C1_A;
c.f0.val.a = 1;
c.f1.tag = IMPORTS_C2_A;
c.f1.val.a = 2;
c.f2.tag = IMPORTS_C3_A;
c.f2.val.a = 3;
c.f3.tag = IMPORTS_C4_A;
c.f3.val.a = 4;
c.f4.tag = IMPORTS_C5_A;
c.f4.val.a = 5;
c.f5.tag = IMPORTS_C6_A;
c.f5.val.a = 6;
imports_variant_casts(&c, &r1, &r2, &r3, &r4, &r5, &r6);
assert(r1.tag == IMPORTS_C1_A && r1.val.a == 1);
assert(r2.tag == IMPORTS_C2_A && r2.val.a == 2);
assert(r3.tag == IMPORTS_C3_A && r3.val.a == 3);
assert(r4.tag == IMPORTS_C4_A && r4.val.a == 4);
assert(r5.tag == IMPORTS_C5_A && r5.val.a == 5);
assert(r6.tag == IMPORTS_C6_A && r6.val.a == 6);
}
{
imports_casts_t c;
imports_c1_t r1;
imports_c2_t r2;
imports_c3_t r3;
imports_c4_t r4;
imports_c5_t r5;
imports_c6_t r6;
c.f0.tag = IMPORTS_C1_B;
c.f0.val.b = 1;
c.f1.tag = IMPORTS_C2_B;
c.f1.val.b = 2;
c.f2.tag = IMPORTS_C3_B;
c.f2.val.b = 3;
c.f3.tag = IMPORTS_C4_B;
c.f3.val.b = 4;
c.f4.tag = IMPORTS_C5_B;
c.f4.val.b = 5;
c.f5.tag = IMPORTS_C6_B;
c.f5.val.b = 6;
imports_variant_casts(&c, &r1, &r2, &r3, &r4, &r5, &r6);
assert(r1.tag == IMPORTS_C1_B && r1.val.b == 1);
assert(r2.tag == IMPORTS_C2_B && r2.val.b == 2);
assert(r3.tag == IMPORTS_C3_B && r3.val.b == 3);
assert(r4.tag == IMPORTS_C4_B && r4.val.b == 4);
assert(r5.tag == IMPORTS_C5_B && r5.val.b == 5);
assert(r6.tag == IMPORTS_C6_B && r6.val.b == 6);
}
{
imports_zeros_t c;
imports_z1_t r1;
imports_z2_t r2;
imports_z3_t r3;
imports_z4_t r4;
c.f0.tag = IMPORTS_Z1_A;
c.f0.val.a = 1;
c.f1.tag = IMPORTS_Z2_A;
c.f1.val.a = 2;
c.f2.tag = IMPORTS_Z3_A;
c.f2.val.a = 3;
c.f3.tag = IMPORTS_Z4_A;
c.f3.val.a = 4;
imports_variant_zeros(&c, &r1, &r2, &r3, &r4);
assert(r1.tag == IMPORTS_Z1_A && r1.val.a == 1);
assert(r2.tag == IMPORTS_Z2_A && r2.val.a == 2);
assert(r3.tag == IMPORTS_Z3_A && r3.val.a == 3);
assert(r4.tag == IMPORTS_Z4_A && r4.val.a == 4);
}
{
imports_zeros_t c;
imports_z1_t r1;
imports_z2_t r2;
imports_z3_t r3;
imports_z4_t r4;
c.f0.tag = IMPORTS_Z1_B;
c.f1.tag = IMPORTS_Z2_B;
c.f2.tag = IMPORTS_Z3_B;
c.f3.tag = IMPORTS_Z4_B;
imports_variant_zeros(&c, &r1, &r2, &r3, &r4);
assert(r1.tag == IMPORTS_Z1_B);
assert(r2.tag == IMPORTS_Z2_B);
assert(r3.tag == IMPORTS_Z3_B);
assert(r4.tag == IMPORTS_Z4_B);
}
{
imports_option_typedef_t a;
a.is_some = false;
bool b = false;
imports_result_typedef_t c;
c.is_err = true;
imports_variant_typedefs(&a, b, &c);
}
{
bool a;
imports_expected_unit_unit_t b;
imports_my_errno_t c;
b.is_err = false;
imports_variant_enums(true, &b, IMPORTS_MY_ERRNO_SUCCESS, &a, &b, &c);
assert(a == false);
assert(b.is_err);
assert(c == IMPORTS_MY_ERRNO_A);
}
}
bool exports_roundtrip_option(exports_option_float32_t *a, uint8_t *ret0) {
if (a->is_some) {
*ret0 = a->val;
}
return a->is_some;
}
void exports_roundtrip_result(exports_expected_u32_float32_t *a, exports_expected_float64_u8_t *ret0) {
ret0->is_err = a->is_err;
if (a->is_err) {
ret0->val.err = a->val.err;
} else {
ret0->val.ok = a->val.ok;
}
}
exports_e1_t exports_roundtrip_enum(exports_e1_t a) {
return a;
}
bool exports_invert_bool(bool a) {
return !a;
}
void exports_variant_casts(exports_casts_t *a, exports_c1_t *ret0, exports_c2_t *ret1, exports_c3_t *ret2, exports_c4_t *ret3, exports_c5_t *ret4, exports_c6_t *ret5) {
*ret0 = a->f0;
*ret1 = a->f1;
*ret2 = a->f2;
*ret3 = a->f3;
*ret4 = a->f4;
*ret5 = a->f5;
}
void exports_variant_zeros(exports_zeros_t *a, exports_z1_t *ret0, exports_z2_t *ret1, exports_z3_t *ret2, exports_z4_t *ret3) {
*ret0 = a->f0;
*ret1 = a->f1;
*ret2 = a->f2;
*ret3 = a->f3;
}
void exports_variant_typedefs(exports_option_typedef_t *a, exports_bool_typedef_t b, exports_result_typedef_t *c) {
}

View File

@@ -0,0 +1,98 @@
wit_bindgen_rust::import!("../../tests/runtime/variants/imports.wit");
wit_bindgen_rust::export!("../../tests/runtime/variants/exports.wit");
use exports::*;
struct Exports;
impl exports::Exports for Exports {
fn test_imports() {
use imports::*;
assert_eq!(roundtrip_option(Some(1.0)), Some(1));
assert_eq!(roundtrip_option(None), None);
assert_eq!(roundtrip_option(Some(2.0)), Some(2));
assert_eq!(roundtrip_result(Ok(2)), Ok(2.0));
assert_eq!(roundtrip_result(Ok(4)), Ok(4.0));
assert_eq!(roundtrip_result(Err(5.3)), Err(5));
assert_eq!(roundtrip_enum(E1::A), E1::A);
assert_eq!(roundtrip_enum(E1::B), E1::B);
assert_eq!(invert_bool(true), false);
assert_eq!(invert_bool(false), true);
let (a1, a2, a3, a4, a5, a6) =
variant_casts((C1::A(1), C2::A(2), C3::A(3), C4::A(4), C5::A(5), C6::A(6.0)));
assert!(matches!(a1, C1::A(1)));
assert!(matches!(a2, C2::A(2)));
assert!(matches!(a3, C3::A(3)));
assert!(matches!(a4, C4::A(4)));
assert!(matches!(a5, C5::A(5)));
assert!(matches!(a6, C6::A(b) if b == 6.0));
let (a1, a2, a3, a4, a5, a6) = variant_casts((
C1::B(1),
C2::B(2.0),
C3::B(3.0),
C4::B(4.0),
C5::B(5.0),
C6::B(6.0),
));
assert!(matches!(a1, C1::B(1)));
assert!(matches!(a2, C2::B(b) if b == 2.0));
assert!(matches!(a3, C3::B(b) if b == 3.0));
assert!(matches!(a4, C4::B(b) if b == 4.0));
assert!(matches!(a5, C5::B(b) if b == 5.0));
assert!(matches!(a6, C6::B(b) if b == 6.0));
let (a1, a2, a3, a4) = variant_zeros((Z1::A(1), Z2::A(2), Z3::A(3.0), Z4::A(4.0)));
assert!(matches!(a1, Z1::A(1)));
assert!(matches!(a2, Z2::A(2)));
assert!(matches!(a3, Z3::A(b) if b == 3.0));
assert!(matches!(a4, Z4::A(b) if b == 4.0));
let (a1, a2, a3, a4) = variant_zeros((Z1::B, Z2::B, Z3::B, Z4::B));
assert!(matches!(a1, Z1::B));
assert!(matches!(a2, Z2::B));
assert!(matches!(a3, Z3::B));
assert!(matches!(a4, Z4::B));
variant_typedefs(None, false, Err(()));
assert_eq!(
variant_enums(true, Ok(()), MyErrno::Success),
(false, Err(()), MyErrno::A)
);
}
fn roundtrip_option(a: Option<f32>) -> Option<u8> {
a.map(|x| x as u8)
}
fn roundtrip_result(a: Result<u32, f32>) -> Result<f64, u8> {
match a {
Ok(a) => Ok(a.into()),
Err(b) => Err(b as u8),
}
}
fn roundtrip_enum(a: E1) -> E1 {
assert_eq!(a, a);
a
}
fn invert_bool(a: bool) -> bool {
!a
}
fn variant_casts(a: Casts) -> Casts {
a
}
fn variant_zeros(a: Zeros) -> Zeros {
a
}
fn variant_typedefs(_: Option<u32>, _: bool, _: Result<u32, ()>) {}
}