@thi.ng/wasm-api 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -1
- package/README.md +25 -31
- package/api.d.ts +36 -3
- package/bridge.d.ts +96 -49
- package/bridge.js +227 -60
- package/dev/custom.zig +1 -0
- package/dev/fieldinfo.zig +135 -0
- package/dev/zig-cache/o/85202d15b9c43c8c66de01ab98d6eb2c/builtin.zig +39 -0
- package/doc/assets/main.js +52 -0
- package/doc/assets/search.js +1 -0
- package/package.json +4 -4
- package/test/custom.zig +12 -0
- package/test/zig-cache/o/117d44467ded6ce3864cde3c180ef73c/builtin.zig +39 -0
- package/zig/core.zig +37 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
-
- **Last updated**: 2022-08-
|
|
3
|
+
- **Last updated**: 2022-08-04T21:21:08Z
|
|
4
4
|
- **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
|
|
5
5
|
|
|
6
6
|
All notable changes to this project will be documented in this file.
|
|
@@ -9,6 +9,23 @@ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelin
|
|
|
9
9
|
**Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
|
|
10
10
|
and/or version bumps of transitive dependencies.
|
|
11
11
|
|
|
12
|
+
## [0.3.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/wasm-api@0.3.0) (2022-08-04)
|
|
13
|
+
|
|
14
|
+
#### 🚀 Features
|
|
15
|
+
|
|
16
|
+
- add i64/u64 support/accessors ([768c8bd](https://github.com/thi-ng/umbrella/commit/768c8bd))
|
|
17
|
+
- add WasmBridge.instantiate, add/update accessors ([0698bae](https://github.com/thi-ng/umbrella/commit/0698bae))
|
|
18
|
+
- add WasmBridge.instantiate() boilerplate
|
|
19
|
+
- add setters for typed scalars & arrays
|
|
20
|
+
- rename derefXX() => getXX() getters
|
|
21
|
+
- update tests
|
|
22
|
+
- major update WasmBridge, add types ([47aa222](https://github.com/thi-ng/umbrella/commit/47aa222))
|
|
23
|
+
- add WasmExports base interface
|
|
24
|
+
- add generics for WasmBridge & IWasmAPI
|
|
25
|
+
- update WasmBridge.init() arg (full WASM exports, not just mem)
|
|
26
|
+
- add WasmBridge.exports field to store WASM module exports
|
|
27
|
+
- add naming conflict check in WasmBridge.getImports()
|
|
28
|
+
|
|
12
29
|
## [0.2.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/wasm-api@0.2.0) (2022-08-01)
|
|
13
30
|
|
|
14
31
|
#### 🚀 Features
|
package/README.md
CHANGED
|
@@ -25,9 +25,10 @@ Modular, extensible API bridge and generic glue code between JS & WebAssembly.
|
|
|
25
25
|
|
|
26
26
|
This package provides a small, generic and modular
|
|
27
27
|
[`WasmBridge`](https://docs.thi.ng/umbrella/wasm-api/classes/WasmBridge.html)
|
|
28
|
-
class as interop basis for hybrid JS/WebAssembly
|
|
29
|
-
only a
|
|
30
|
-
|
|
28
|
+
class as interop basis and a much reduced boilerplate for hybrid JS/WebAssembly
|
|
29
|
+
applications. At the moment only a minimal core API is provided (i.e. for debug
|
|
30
|
+
output, string, pointer, typed array accessors [8/16/32/64 bit (u)ints, 32/64
|
|
31
|
+
bit floats]), but in the future we aim to also supply support modules for DOM
|
|
31
32
|
manipulation, WebGL, WebGPU, WebAudio etc.
|
|
32
33
|
|
|
33
34
|
In general, all languages with a WebAssembly target are supported, however
|
|
@@ -82,25 +83,26 @@ export const bridge = new WasmBridge({ custom: new CustomAPI() });
|
|
|
82
83
|
```
|
|
83
84
|
|
|
84
85
|
In Zig (or any other language of your choice) we can then utilize this custom
|
|
85
|
-
API like so (also see example further below in this readme):
|
|
86
|
+
API like so (Please also see example further below in this readme):
|
|
86
87
|
|
|
87
88
|
```zig
|
|
89
|
+
// Import JS core API
|
|
88
90
|
const js = @import("wasmapi");
|
|
89
91
|
|
|
90
92
|
/// JS external to fill vec2 w/ random values
|
|
91
93
|
extern fn custom_randomVec2(addr: usize) void;
|
|
92
94
|
|
|
93
95
|
export fn test_randomVec2() void {
|
|
94
|
-
|
|
96
|
+
var foo = [2]f32{ 0, 0 };
|
|
95
97
|
|
|
96
98
|
// print original
|
|
97
|
-
|
|
99
|
+
js.printF32Array(foo[0..]);
|
|
98
100
|
|
|
99
101
|
// populate foo with random numbers
|
|
100
|
-
|
|
102
|
+
custom_randomVec2(@ptrToInt(&foo));
|
|
101
103
|
|
|
102
104
|
// print result
|
|
103
|
-
|
|
105
|
+
js.printF32Array(foo[0..]);
|
|
104
106
|
}
|
|
105
107
|
```
|
|
106
108
|
|
|
@@ -180,7 +182,7 @@ node --experimental-repl-await
|
|
|
180
182
|
> const wasmApi = await import("@thi.ng/wasm-api");
|
|
181
183
|
```
|
|
182
184
|
|
|
183
|
-
Package sizes (gzipped, pre-treeshake): ESM: 1.
|
|
185
|
+
Package sizes (gzipped, pre-treeshake): ESM: 1.63 KB
|
|
184
186
|
|
|
185
187
|
## Dependencies
|
|
186
188
|
|
|
@@ -195,34 +197,25 @@ Package sizes (gzipped, pre-treeshake): ESM: 1.21 KB
|
|
|
195
197
|
[Generated API docs](https://docs.thi.ng/umbrella/wasm-api/)
|
|
196
198
|
|
|
197
199
|
```ts
|
|
198
|
-
import { WasmBridge } from "@thi.ng/wasm-api";
|
|
200
|
+
import { WasmBridge, WasmExports } from "@thi.ng/wasm-api";
|
|
199
201
|
import { readFileSync } from "fs";
|
|
200
202
|
|
|
201
203
|
// WASM exports from our dummy module (below)
|
|
202
|
-
interface App {
|
|
203
|
-
memory: WebAssembly.Memory;
|
|
204
|
+
interface App extends WasmExports {
|
|
204
205
|
start: () => void;
|
|
205
206
|
}
|
|
206
207
|
|
|
207
208
|
(async () => {
|
|
208
209
|
// new API bridge with defaults
|
|
209
210
|
// (i.e. no child API modules and using console logger)
|
|
210
|
-
const bridge = new WasmBridge();
|
|
211
|
+
const bridge = new WasmBridge<App>();
|
|
211
212
|
|
|
212
213
|
// instantiate WASM module using imports provided by the bridge
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
bridge.getImports()
|
|
216
|
-
);
|
|
214
|
+
// this also initializes any bindings & bridge child APIs (if any)
|
|
215
|
+
await bridge.instantiate(readFileSync("hello.wasm"));
|
|
217
216
|
|
|
218
|
-
//
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
// init bindings & child APIs (if any)
|
|
222
|
-
await bridge.init(app.memory);
|
|
223
|
-
|
|
224
|
-
// call a WASM function
|
|
225
|
-
app.start();
|
|
217
|
+
// call an exported WASM function
|
|
218
|
+
bridge.exports.start();
|
|
226
219
|
})();
|
|
227
220
|
```
|
|
228
221
|
|
|
@@ -238,16 +231,17 @@ export fn start() void {
|
|
|
238
231
|
}
|
|
239
232
|
```
|
|
240
233
|
|
|
241
|
-
The WASM binary can be built
|
|
242
|
-
.zig file(s) to your `build.zig` and/or source
|
|
234
|
+
The WASM binary can be built using the following command (or for more complex
|
|
235
|
+
scenarios add the supplied .zig file(s) to your `build.zig` and/or source
|
|
236
|
+
folder):
|
|
243
237
|
|
|
244
238
|
```bash
|
|
245
239
|
# compile WASM binary
|
|
246
240
|
zig build-lib \
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
241
|
+
--pkg-begin wasmapi node_modules/@thi.ng/wasm-api/zig/core.zig --pkg-end \
|
|
242
|
+
-target wasm32-freestanding \
|
|
243
|
+
-O ReleaseSmall -dynamic --strip \
|
|
244
|
+
hello.zig
|
|
251
245
|
|
|
252
246
|
# disassemble WASM
|
|
253
247
|
wasm-dis -o hello.wast hello.wasm
|
package/api.d.ts
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
import type { Fn } from "@thi.ng/api";
|
|
1
|
+
import type { Fn, Fn2 } from "@thi.ng/api";
|
|
2
2
|
import type { WasmBridge } from "./bridge.js";
|
|
3
|
+
export declare type BigIntArray = bigint[] | BigInt64Array | BigUint64Array;
|
|
3
4
|
/**
|
|
4
5
|
* Common interface for WASM/JS child APIs which will be used in combination
|
|
5
6
|
* with a parent {@link WasmBridge}.
|
|
7
|
+
*
|
|
8
|
+
* @remarks
|
|
9
|
+
* The generic type param is optional and only used if the API is requiring
|
|
10
|
+
* certain exports declared by WASM module.
|
|
6
11
|
*/
|
|
7
|
-
export interface IWasmAPI {
|
|
12
|
+
export interface IWasmAPI<T extends WasmExports = WasmExports> {
|
|
8
13
|
/**
|
|
9
14
|
* Called by {@link WasmBridge.init} to initialize all child APIs (async)
|
|
10
15
|
* after the WASM module has been instantiated. If the method returns false
|
|
@@ -12,7 +17,7 @@ export interface IWasmAPI {
|
|
|
12
17
|
*
|
|
13
18
|
* @param parent
|
|
14
19
|
*/
|
|
15
|
-
init(parent: WasmBridge): Promise<boolean>;
|
|
20
|
+
init(parent: WasmBridge<T>): Promise<boolean>;
|
|
16
21
|
/**
|
|
17
22
|
* Returns an object of this child API's declared WASM imports. Be aware
|
|
18
23
|
* imports from all child APIs will be merged into a single flat namespace,
|
|
@@ -20,6 +25,29 @@ export interface IWasmAPI {
|
|
|
20
25
|
*/
|
|
21
26
|
getImports(): WebAssembly.ModuleImports;
|
|
22
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Base interface of exports declared by the WASM module. At the very least, the
|
|
30
|
+
* module needs to export its memory.
|
|
31
|
+
*
|
|
32
|
+
* @remarks
|
|
33
|
+
* This interface is supposed to be extended with the concrete exports defined
|
|
34
|
+
* by your WASM module and is used as generic type param for {@link WasmBridge}
|
|
35
|
+
* and any {@link IWasmAPI} bridge modules. These exports can obtained via
|
|
36
|
+
* {@link WasmBridge.exports} where they will be stored during the execution of
|
|
37
|
+
* {@link WasmBridge.init}.
|
|
38
|
+
*/
|
|
39
|
+
export interface WasmExports {
|
|
40
|
+
/**
|
|
41
|
+
* The WASM module's linear memory buffer. The `WasmBridge` automatically
|
|
42
|
+
* creates various typed views of that memory.
|
|
43
|
+
*/
|
|
44
|
+
memory: WebAssembly.Memory;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Core API of WASM imports defined by the {@link WasmBridge}. The same
|
|
48
|
+
* functions are declared as bindings in `/zig/core.zig`. Also see this file for
|
|
49
|
+
* documentation of each function...
|
|
50
|
+
*/
|
|
23
51
|
export interface CoreAPI {
|
|
24
52
|
printI8: Fn<number, void>;
|
|
25
53
|
printU8: Fn<number, void>;
|
|
@@ -30,6 +58,9 @@ export interface CoreAPI {
|
|
|
30
58
|
printI32: Fn<number, void>;
|
|
31
59
|
printU32: Fn<number, void>;
|
|
32
60
|
printU32Hex: Fn<number, void>;
|
|
61
|
+
_printI64: Fn2<number, number, void>;
|
|
62
|
+
_printU64: Fn2<number, number, void>;
|
|
63
|
+
_printU64Hex: Fn2<number, number, void>;
|
|
33
64
|
printF32: Fn<number, void>;
|
|
34
65
|
printF64: Fn<number, void>;
|
|
35
66
|
_printI8Array: (addr: number, len: number) => void;
|
|
@@ -38,6 +69,8 @@ export interface CoreAPI {
|
|
|
38
69
|
_printU16Array: (addr: number, len: number) => void;
|
|
39
70
|
_printI32Array: (addr: number, len: number) => void;
|
|
40
71
|
_printU32Array: (addr: number, len: number) => void;
|
|
72
|
+
_printI64Array: (addr: number, len: number) => void;
|
|
73
|
+
_printU64Array: (addr: number, len: number) => void;
|
|
41
74
|
_printF32Array: (addr: number, len: number) => void;
|
|
42
75
|
_printF64Array: (addr: number, len: number) => void;
|
|
43
76
|
_printStr0: (addr: number) => void;
|
package/bridge.d.ts
CHANGED
|
@@ -1,7 +1,24 @@
|
|
|
1
|
+
import type { NumericArray } from "@thi.ng/api";
|
|
1
2
|
import type { ILogger } from "@thi.ng/logger";
|
|
2
|
-
import type { CoreAPI, IWasmAPI } from "./api.js";
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
import type { BigIntArray, CoreAPI, IWasmAPI, WasmExports } from "./api.js";
|
|
4
|
+
/**
|
|
5
|
+
* The main interop API bridge between the JS host environment and a WebAssembly
|
|
6
|
+
* module. This class provides a small core API with various typed accessors and
|
|
7
|
+
* utils to exchange data (scalars, arrays, strings etc.) via the WASM module's
|
|
8
|
+
* memory.
|
|
9
|
+
*
|
|
10
|
+
* @remarks
|
|
11
|
+
* All typed memory accessors are assuming the given lookup addresses are
|
|
12
|
+
* properly aligned to the corresponding primitive types (e.g. f32 values are
|
|
13
|
+
* aligned to 4 byte boundaries, f64 to 8 bytes etc.) Unaligned access is
|
|
14
|
+
* explicitly **not supported**! If you need such, please refer to other
|
|
15
|
+
* mechanisms like JS `DataView`...
|
|
16
|
+
*
|
|
17
|
+
* 64bit integers are handled via JS `BigInt` and hence require the host env to
|
|
18
|
+
* support it. No polyfill is provided.
|
|
19
|
+
*/
|
|
20
|
+
export declare class WasmBridge<T extends WasmExports = WasmExports> {
|
|
21
|
+
modules: Record<string, IWasmAPI<T>>;
|
|
5
22
|
logger: ILogger;
|
|
6
23
|
i8: Int8Array;
|
|
7
24
|
u8: Uint8Array;
|
|
@@ -9,60 +26,90 @@ export declare class WasmBridge {
|
|
|
9
26
|
u16: Uint16Array;
|
|
10
27
|
i32: Int32Array;
|
|
11
28
|
u32: Uint32Array;
|
|
29
|
+
i64: BigInt64Array;
|
|
30
|
+
u64: BigUint64Array;
|
|
12
31
|
f32: Float32Array;
|
|
13
32
|
f64: Float64Array;
|
|
14
33
|
utf8Decoder: TextDecoder;
|
|
15
34
|
utf8Encoder: TextEncoder;
|
|
16
35
|
core: CoreAPI;
|
|
17
|
-
|
|
18
|
-
|
|
36
|
+
exports: T;
|
|
37
|
+
constructor(modules?: Record<string, IWasmAPI<T>>, logger?: ILogger);
|
|
19
38
|
/**
|
|
20
|
-
*
|
|
21
|
-
*
|
|
39
|
+
* Instantiates WASM module from given `src` (and optional provided extra
|
|
40
|
+
* imports), then automatically calls {@link WasmBridge.init} with the
|
|
41
|
+
* modules exports.
|
|
42
|
+
*
|
|
43
|
+
* @remarks
|
|
44
|
+
* If the given `src` is a `Response` or `Promise<Response>`, the module
|
|
45
|
+
* will be instantiated via `WebAssembly.instantiateStreaming()`, otherwise
|
|
46
|
+
* the non-streaming version will be used.
|
|
47
|
+
*
|
|
48
|
+
* @param src
|
|
49
|
+
* @param imports
|
|
22
50
|
*/
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
51
|
+
instantiate(src: Response | BufferSource | PromiseLike<Response | BufferSource>, imports?: WebAssembly.Imports): Promise<boolean>;
|
|
52
|
+
/**
|
|
53
|
+
* Receives the WASM module's exports, stores the for future reference and
|
|
54
|
+
* then initializes all declared bridge child API modules. Returns false if
|
|
55
|
+
* any of the module initializations failed.
|
|
56
|
+
*
|
|
57
|
+
* @param exports
|
|
58
|
+
*/
|
|
59
|
+
init(exports: T): Promise<boolean>;
|
|
60
|
+
/**
|
|
61
|
+
* Required use for WASM module instantiation to provide JS imports to the
|
|
62
|
+
* module. Returns an object of all WASM imports declared by the bridge core
|
|
63
|
+
* API and any provided bridge API modules.
|
|
64
|
+
*
|
|
65
|
+
* @remarks
|
|
66
|
+
* Since all declared imports will be merged into a single flat namespace,
|
|
67
|
+
* it's recommended to use per-module naming prefixes to avoid clashes. If
|
|
68
|
+
* there're any naming clashes, this function will throw an error.
|
|
69
|
+
*/
|
|
70
|
+
getImports(): WebAssembly.Imports;
|
|
71
|
+
getI8(addr: number): number;
|
|
72
|
+
getU8(addr: number): number;
|
|
73
|
+
getI16(addr: number): number;
|
|
74
|
+
getU16(addr: number): number;
|
|
75
|
+
getI32(addr: number): number;
|
|
76
|
+
getU32(addr: number): number;
|
|
77
|
+
getI64(addr: number): bigint;
|
|
78
|
+
getU64(addr: number): bigint;
|
|
79
|
+
getF32(addr: number): number;
|
|
80
|
+
getF64(addr: number): number;
|
|
81
|
+
setI8(addr: number, x: number): this;
|
|
82
|
+
setU8(addr: number, x: number): this;
|
|
83
|
+
setI16(addr: number, x: number): this;
|
|
84
|
+
setU16(addr: number, x: number): this;
|
|
85
|
+
setI32(addr: number, x: number): this;
|
|
86
|
+
setU32(addr: number, x: number): this;
|
|
87
|
+
setI64(addr: number, x: bigint): this;
|
|
88
|
+
setU64(addr: number, x: bigint): this;
|
|
89
|
+
setF32(addr: number, x: number): this;
|
|
90
|
+
setF64(addr: number, x: number): this;
|
|
91
|
+
getI8Array(addr: number, len: number): Int8Array;
|
|
92
|
+
getU8Array(addr: number, len: number): Uint8Array;
|
|
93
|
+
getI16Array(addr: number, len: number): Int16Array;
|
|
94
|
+
getU16Array(addr: number, len: number): Uint16Array;
|
|
95
|
+
getI32Array(addr: number, len: number): Int32Array;
|
|
96
|
+
getU32Array(addr: number, len: number): Uint32Array;
|
|
97
|
+
getI64Array(addr: number, len: number): BigInt64Array;
|
|
98
|
+
getU64Array(addr: number, len: number): BigUint64Array;
|
|
99
|
+
getF32Array(addr: number, len: number): Float32Array;
|
|
100
|
+
getF64Array(addr: number, len: number): Float64Array;
|
|
101
|
+
setI8Array(addr: number, buf: NumericArray): this;
|
|
102
|
+
setU8Array(addr: number, buf: NumericArray): this;
|
|
103
|
+
setI16Array(addr: number, buf: NumericArray): this;
|
|
104
|
+
setU16Array(addr: number, buf: NumericArray): this;
|
|
105
|
+
setI32Array(addr: number, buf: NumericArray): this;
|
|
106
|
+
setU32Array(addr: number, buf: NumericArray): this;
|
|
107
|
+
setI64Array(addr: number, buf: BigIntArray): this;
|
|
108
|
+
setU64Array(addr: number, buf: BigIntArray): this;
|
|
109
|
+
setF32Array(addr: number, buf: NumericArray): this;
|
|
110
|
+
setF64Array(addr: number, buf: NumericArray): this;
|
|
64
111
|
getString(addr: number, len?: number): string;
|
|
65
|
-
getElementById(addr: number, len?: number): HTMLElement | null;
|
|
66
112
|
setString(str: string, addr: number, maxBytes: number, terminate?: boolean): number;
|
|
113
|
+
getElementById(addr: number, len?: number): HTMLElement;
|
|
67
114
|
}
|
|
68
115
|
//# sourceMappingURL=bridge.d.ts.map
|