feat: add a histrical wit-bindgen
This commit is contained in:
@@ -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
|
||||
@@ -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])
|
||||
@@ -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(())
|
||||
}
|
||||
@@ -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()
|
||||
@@ -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>>)
|
||||
292
__wasm/wit-bindgen-sample/wit-bindgen/tests/runtime/lists/wasm.c
Normal file
292
__wasm/wit-bindgen-sample/wit-bindgen/tests/runtime/lists/wasm.c
Normal 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;
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user