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,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()
}
}