@thi.ng/wasm-api 1.0.0 → 1.0.1
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 +1 -1
- package/README.md +86 -149
- package/include/wasmapi.h +0 -2
- package/package.json +2 -2
- package/zig/lib.zig +0 -3
- package/include/wasmapi_types.h +0 -35
- package/zig/types.zig +0 -52
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -59,8 +59,7 @@ WebGL, WebGPU, WebAudio etc. is being actively worked on.
|
|
|
59
59
|
for (currently) Zig & TypeScript and C11. For TS fully type checked and
|
|
60
60
|
memory-mapped (zero-copy) accessors of WASM-side data are generated. In
|
|
61
61
|
principle, all languages with a WASM target are supported, however currently
|
|
62
|
-
only bindings for these mentioned langs are included.
|
|
63
|
-
custom bindings, e.g. based on the flexible primitives provided here.
|
|
62
|
+
only bindings for these mentioned langs are included.
|
|
64
63
|
8. [CLI
|
|
65
64
|
frontend/utility](https://github.com/thi-ng/umbrella/blob/develop/packages/wasm-api-bindgen/README.md#cli-generator)
|
|
66
65
|
for the code generator(s)
|
|
@@ -83,40 +82,40 @@ following example provides a brief overview:
|
|
|
83
82
|
import { IWasmAPI, WasmBridge } from "@thi.ng/wasm-api";
|
|
84
83
|
|
|
85
84
|
export class CustomAPI implements IWasmAPI {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
85
|
+
// Unique API module identifier to group WASM imports,
|
|
86
|
+
// must match ID used by native code (see further below).
|
|
87
|
+
readonly id = "custom";
|
|
88
|
+
// optionally list IDs of other API modules this module depends on
|
|
89
|
+
// these are used to infer the correct initialization order
|
|
90
|
+
readonly dependencies = [];
|
|
91
|
+
|
|
92
|
+
parent!: WasmBridge;
|
|
93
|
+
|
|
94
|
+
async init(parent: WasmBridge) {
|
|
95
|
+
this.parent = parent;
|
|
96
|
+
this.parent.logger.debug("initializing custom API");
|
|
97
|
+
|
|
98
|
+
// any other tasks you might need to do...
|
|
99
|
+
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Returns object of functions to import as externals into the
|
|
105
|
+
* WASM module during instantiation. These imports are merged
|
|
106
|
+
* into a larger imports object alongside the bridge's core API...
|
|
107
|
+
*/
|
|
108
|
+
getImports(): WebAssembly.Imports {
|
|
109
|
+
return {
|
|
110
|
+
/**
|
|
111
|
+
* Writes `num` random float32 numbers from given address
|
|
112
|
+
*/
|
|
113
|
+
fillRandom: (addr: number, num: number) => {
|
|
114
|
+
addr >>>= 2;
|
|
115
|
+
while(num-- > 0) this.parent.f32[addr++] = Math.random();
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
}
|
|
120
119
|
}
|
|
121
120
|
```
|
|
122
121
|
|
|
@@ -151,16 +150,16 @@ const js = @import("wasmapi");
|
|
|
151
150
|
const custom = @import("custom.zig");
|
|
152
151
|
|
|
153
152
|
export fn test_randomVec4() void {
|
|
154
|
-
|
|
153
|
+
var foo = [4]f32{ 1, 2, 3, 4 };
|
|
155
154
|
|
|
156
|
-
|
|
157
|
-
|
|
155
|
+
// print original
|
|
156
|
+
js.printF32Array(foo[0..]);
|
|
158
157
|
|
|
159
|
-
|
|
160
|
-
|
|
158
|
+
// populate foo with random numbers
|
|
159
|
+
custom.fillRandom(&foo, foo.len);
|
|
161
160
|
|
|
162
|
-
|
|
163
|
-
|
|
161
|
+
// print result
|
|
162
|
+
js.printF32Array(foo[0..]);
|
|
164
163
|
}
|
|
165
164
|
```
|
|
166
165
|
|
|
@@ -190,6 +189,15 @@ and
|
|
|
190
189
|
[`setString()`](https://docs.thi.ng/umbrella/wasm-api/classes/WasmBridge.html#setString)
|
|
191
190
|
for details.
|
|
192
191
|
|
|
192
|
+
Furthermore, the package provides these string wrapper types:
|
|
193
|
+
|
|
194
|
+
- [`WasmStringPtr`](https://docs.thi.ng/umbrella/wasm-api/classes/WasmStringPtr.html)
|
|
195
|
+
- [`WasmStringSlice`](https://docs.thi.ng/umbrella/wasm-api/classes/WasmStringSlice.html)
|
|
196
|
+
|
|
197
|
+
Finally, see more information in the
|
|
198
|
+
[@thi.ng/wasm-api-bindgen](https://github.com/thi-ng/umbrella/blob/develop/packages/wasm-api-bindgen/README.md#string-handling)
|
|
199
|
+
package readme.
|
|
200
|
+
|
|
193
201
|
### Memory allocations
|
|
194
202
|
|
|
195
203
|
If explicitly enabled on the WASM side, the `WasmBridge` includes support for
|
|
@@ -199,9 +207,9 @@ The actual allocator is implementation specific and suitable generic mechanisms
|
|
|
199
207
|
are defined for both the included Zig & C bindings. Please see for further
|
|
200
208
|
reference:
|
|
201
209
|
|
|
202
|
-
- [`/zig/lib.zig`](https://github.com/thi-ng/umbrella/blob/develop/packages/wasm-api/zig/lib.zig#
|
|
210
|
+
- [`/zig/lib.zig`](https://github.com/thi-ng/umbrella/blob/develop/packages/wasm-api/zig/lib.zig#L34-L68):
|
|
203
211
|
comments about WASM-side allocator handling in Zig
|
|
204
|
-
- [`/include/wasmapi.h`](https://github.com/thi-ng/umbrella/blob/develop/packages/wasm-api/include/wasmapi.h#
|
|
212
|
+
- [`/include/wasmapi.h`](https://github.com/thi-ng/umbrella/blob/develop/packages/wasm-api/include/wasmapi.h#L18-L28):
|
|
205
213
|
comments about WASM-side allocator handling in C/C++
|
|
206
214
|
- [`WasmBridge.allocate()`](https://docs.thi.ng/umbrella/wasm-api/classes/WasmBridge.html#allocate):
|
|
207
215
|
allocating memory from JS side
|
|
@@ -217,22 +225,22 @@ for more details...
|
|
|
217
225
|
|
|
218
226
|
```ts
|
|
219
227
|
try {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
228
|
+
// allocate 256 bytes of memory for passing a string to WASM side
|
|
229
|
+
// the function returns a tuple of `[address, len]`
|
|
230
|
+
const [addr, len] = bridge.allocate(256);
|
|
223
231
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
232
|
+
// write zero terminated string to reserved memory (max. `len` bytes)
|
|
233
|
+
// function returns number of bytes written (excl. sentinel)
|
|
234
|
+
const num = bridge.setString("hello WASM world!", addr, len, true);
|
|
227
235
|
|
|
228
|
-
|
|
229
|
-
|
|
236
|
+
// call WASM function doing something w/ the string
|
|
237
|
+
bridge.exports.doSomethingWithString(addr, num);
|
|
230
238
|
|
|
231
|
-
|
|
232
|
-
|
|
239
|
+
// cleanup
|
|
240
|
+
bridge.free([addr, len]);
|
|
233
241
|
} catch(e) {
|
|
234
|
-
|
|
235
|
-
|
|
242
|
+
// deal with allocation error
|
|
243
|
+
// ...
|
|
236
244
|
}
|
|
237
245
|
```
|
|
238
246
|
|
|
@@ -288,8 +296,8 @@ Since v0.15.0, the supplied Zig core bindings lib also includes a
|
|
|
288
296
|
for similar dealings on the Zig side of the application. For example, in the
|
|
289
297
|
[@thi.ng/wasm-api-dom](https://github.com/thi-ng/umbrella/blob/develop/packages/wasm-api-dom/)
|
|
290
298
|
&
|
|
291
|
-
[@thi.ng/wasm-api-
|
|
292
|
-
|
|
299
|
+
[@thi.ng/wasm-api-schedule](https://github.com/thi-ng/umbrella/blob/develop/packages/wasm-api-schedule/)
|
|
300
|
+
packages this is used to manage Zig event listeners.
|
|
293
301
|
|
|
294
302
|
## Status
|
|
295
303
|
|
|
@@ -364,21 +372,21 @@ import { readFileSync } from "fs";
|
|
|
364
372
|
|
|
365
373
|
// WASM exports from our dummy module (below)
|
|
366
374
|
interface App extends WasmExports {
|
|
367
|
-
|
|
375
|
+
start: () => void;
|
|
368
376
|
}
|
|
369
377
|
|
|
370
378
|
(async () => {
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
379
|
+
// new API bridge with defaults
|
|
380
|
+
// (i.e. no child API modules and using console logger)
|
|
381
|
+
const bridge = new WasmBridge<App>();
|
|
374
382
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
383
|
+
// instantiate WASM module using imports provided by the bridge
|
|
384
|
+
// this also initializes any bindings & bridge child APIs (if any)
|
|
385
|
+
// (also accepts a fetch() `Response` as input)
|
|
386
|
+
await bridge.instantiate(readFileSync("hello.wasm"));
|
|
379
387
|
|
|
380
|
-
|
|
381
|
-
|
|
388
|
+
// call an exported WASM function
|
|
389
|
+
bridge.exports.start();
|
|
382
390
|
})();
|
|
383
391
|
```
|
|
384
392
|
|
|
@@ -386,19 +394,15 @@ interface App extends WasmExports {
|
|
|
386
394
|
|
|
387
395
|
Requires [Zig](https://ziglang.org) to be installed:
|
|
388
396
|
|
|
389
|
-
```zig
|
|
397
|
+
```zig tangle:export/hello.zig
|
|
390
398
|
//! Example Zig application (hello.zig)
|
|
391
399
|
|
|
392
400
|
/// import externals
|
|
393
401
|
/// see build command for configuration
|
|
394
402
|
const js = @import("wasmapi");
|
|
395
|
-
const std = @import("std");
|
|
396
|
-
|
|
397
|
-
// set custom memory allocator (here to disable)
|
|
398
|
-
pub const WASM_ALLOCATOR: ?std.mem.Allocator = null;
|
|
399
403
|
|
|
400
404
|
export fn start() void {
|
|
401
|
-
|
|
405
|
+
js.printStr("hello world!");
|
|
402
406
|
}
|
|
403
407
|
```
|
|
404
408
|
|
|
@@ -409,10 +413,10 @@ folder):
|
|
|
409
413
|
```bash
|
|
410
414
|
# compile WASM binary
|
|
411
415
|
zig build-lib \
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
+
--pkg-begin wasmapi node_modules/@thi.ng/wasm-api/zig/lib.zig --pkg-end \
|
|
417
|
+
-target wasm32-freestanding \
|
|
418
|
+
-O ReleaseSmall -dynamic \
|
|
419
|
+
hello.zig
|
|
416
420
|
|
|
417
421
|
# disassemble WASM
|
|
418
422
|
wasm-dis -o hello.wast hello.wasm
|
|
@@ -451,11 +455,11 @@ The resulting WASM:
|
|
|
451
455
|
|
|
452
456
|
Requires [Emscripten](https://emscripten.org/) to be installed:
|
|
453
457
|
|
|
454
|
-
```c
|
|
458
|
+
```c tangle:export/hello.c
|
|
455
459
|
#include <wasmapi.h>
|
|
456
460
|
|
|
457
|
-
void
|
|
458
|
-
|
|
461
|
+
void WASMAPI_KEEP start() {
|
|
462
|
+
wasm_printStrZ("hello world!");
|
|
459
463
|
}
|
|
460
464
|
```
|
|
461
465
|
|
|
@@ -467,73 +471,6 @@ emcc -Os -Inode_modules/@thi.ng/wasm-api/include \
|
|
|
467
471
|
-o hello.wasm hello.c
|
|
468
472
|
```
|
|
469
473
|
|
|
470
|
-
Resulting WASM:
|
|
471
|
-
|
|
472
|
-
```wasm
|
|
473
|
-
(module
|
|
474
|
-
(type $i32_=>_none (func (param i32)))
|
|
475
|
-
(type $none_=>_none (func))
|
|
476
|
-
(type $i32_=>_i32 (func (param i32) (result i32)))
|
|
477
|
-
(type $none_=>_i32 (func (result i32)))
|
|
478
|
-
(type $i32_i32_=>_none (func (param i32 i32)))
|
|
479
|
-
(import "wasmapi" "_printStr0" (func $fimport$0 (param i32)))
|
|
480
|
-
(global $global$0 (mut i32) (i32.const 5243936))
|
|
481
|
-
(memory $0 256 256)
|
|
482
|
-
(data (i32.const 1024) "hello world!")
|
|
483
|
-
(table $0 2 2 funcref)
|
|
484
|
-
(elem (i32.const 1) $0)
|
|
485
|
-
(export "memory" (memory $0))
|
|
486
|
-
(export "_wasm_allocate" (func $1))
|
|
487
|
-
(export "_wasm_free" (func $2))
|
|
488
|
-
(export "start" (func $3))
|
|
489
|
-
(export "__indirect_function_table" (table $0))
|
|
490
|
-
(export "_initialize" (func $0))
|
|
491
|
-
(export "__errno_location" (func $7))
|
|
492
|
-
(export "stackSave" (func $4))
|
|
493
|
-
(export "stackRestore" (func $5))
|
|
494
|
-
(export "stackAlloc" (func $6))
|
|
495
|
-
(func $0
|
|
496
|
-
(nop)
|
|
497
|
-
)
|
|
498
|
-
(func $1 (param $0 i32) (result i32)
|
|
499
|
-
(i32.const 0)
|
|
500
|
-
)
|
|
501
|
-
(func $2 (param $0 i32) (param $1 i32)
|
|
502
|
-
(nop)
|
|
503
|
-
)
|
|
504
|
-
(func $3
|
|
505
|
-
(call $fimport$0
|
|
506
|
-
(i32.const 1024)
|
|
507
|
-
)
|
|
508
|
-
)
|
|
509
|
-
(func $4 (result i32)
|
|
510
|
-
(global.get $global$0)
|
|
511
|
-
)
|
|
512
|
-
(func $5 (param $0 i32)
|
|
513
|
-
(global.set $global$0
|
|
514
|
-
(local.get $0)
|
|
515
|
-
)
|
|
516
|
-
)
|
|
517
|
-
(func $6 (param $0 i32) (result i32)
|
|
518
|
-
(global.set $global$0
|
|
519
|
-
(local.tee $0
|
|
520
|
-
(i32.and
|
|
521
|
-
(i32.sub
|
|
522
|
-
(global.get $global$0)
|
|
523
|
-
(local.get $0)
|
|
524
|
-
)
|
|
525
|
-
(i32.const -16)
|
|
526
|
-
)
|
|
527
|
-
)
|
|
528
|
-
)
|
|
529
|
-
(local.get $0)
|
|
530
|
-
)
|
|
531
|
-
(func $7 (result i32)
|
|
532
|
-
(i32.const 1040)
|
|
533
|
-
)
|
|
534
|
-
)
|
|
535
|
-
```
|
|
536
|
-
|
|
537
474
|
## Authors
|
|
538
475
|
|
|
539
476
|
Karsten Schmidt
|
package/include/wasmapi.h
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thi.ng/wasm-api",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Generic, modular, extensible API bridge and infrastructure for hybrid JS & WebAssembly projects",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -110,5 +110,5 @@
|
|
|
110
110
|
"status": "alpha",
|
|
111
111
|
"year": 2022
|
|
112
112
|
},
|
|
113
|
-
"gitHead": "
|
|
113
|
+
"gitHead": "8d59e559a576ecb3d2c2d13edf5c3146df95d6ac\n"
|
|
114
114
|
}
|
package/zig/lib.zig
CHANGED
package/include/wasmapi_types.h
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
#pragma once
|
|
2
|
-
|
|
3
|
-
#ifdef __cplusplus
|
|
4
|
-
extern "C" {
|
|
5
|
-
#endif
|
|
6
|
-
|
|
7
|
-
#include <stddef.h>
|
|
8
|
-
|
|
9
|
-
typedef char* WASM_StringPtr;
|
|
10
|
-
typedef const char* WASM_ConstStringPtr;
|
|
11
|
-
|
|
12
|
-
typedef void* WASM_OpaquePtr;
|
|
13
|
-
typedef const void* WASM_ConstOpaquePtr;
|
|
14
|
-
|
|
15
|
-
// slice-based string
|
|
16
|
-
typedef struct { WASM_StringPtr ptr; size_t len; } WASM_String;
|
|
17
|
-
typedef struct { WASM_ConstStringPtr ptr; size_t len; } WASM_ConstString;
|
|
18
|
-
|
|
19
|
-
// defines slice wrapper structs for given pointer types
|
|
20
|
-
#define WASMAPI_SLICE(PREFIX, NAME, PTR, CONSTPTR) \
|
|
21
|
-
typedef struct { PTR* ptr; size_t len; } PREFIX##NAME##Slice; \
|
|
22
|
-
typedef struct { CONSTPTR* ptr; size_t len; } PREFIX##Const##NAME##Slice;
|
|
23
|
-
|
|
24
|
-
// slice of string slices
|
|
25
|
-
WASMAPI_SLICE(WASM_, String, WASM_String, WASM_ConstString)
|
|
26
|
-
|
|
27
|
-
// slice of string pointers
|
|
28
|
-
WASMAPI_SLICE(WASM_, StringPtr, WASM_StringPtr, WASM_ConstStringPtr)
|
|
29
|
-
|
|
30
|
-
// slice of opaque pointers
|
|
31
|
-
WASMAPI_SLICE(WASM_, OpaquePtr, WASM_OpaquePtr, WASM_ConstOpaquePtr)
|
|
32
|
-
|
|
33
|
-
#ifdef __cplusplus
|
|
34
|
-
}
|
|
35
|
-
#endif
|
package/zig/types.zig
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
//! Common helper types used by the thi.ng/wasm-api code gen
|
|
2
|
-
//! None of these type have any further dependencies on the main wasm-api package
|
|
3
|
-
|
|
4
|
-
/// Higher-order generic slice wrapper for `extern struct` use cases
|
|
5
|
-
/// S = slice type
|
|
6
|
-
/// P = pointer type
|
|
7
|
-
pub fn Slice(comptime S: type, comptime P: type) type {
|
|
8
|
-
return extern struct {
|
|
9
|
-
ptr: P = @as(S, &.{}).ptr,
|
|
10
|
-
len: usize = 0,
|
|
11
|
-
|
|
12
|
-
pub inline fn wrap(slice: S) @This() {
|
|
13
|
-
return .{
|
|
14
|
-
.ptr = @ptrCast(P, slice.ptr),
|
|
15
|
-
.len = slice.len,
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
pub inline fn toSlice(self: *@This()) S {
|
|
20
|
-
return @ptrCast(*S, self).*;
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
pub const StringPtr = [*:0]u8;
|
|
26
|
-
pub const ConstStringPtr = [*:0]const u8;
|
|
27
|
-
|
|
28
|
-
/// `[]u8` slice wrapper for `extern struct` use cases
|
|
29
|
-
pub const String = Slice([]u8, StringPtr);
|
|
30
|
-
/// `[]const u8` slice wrapper for `extern struct` use cases
|
|
31
|
-
pub const ConstString = Slice([]const u8, ConstStringPtr);
|
|
32
|
-
|
|
33
|
-
/// Slice of `String`s
|
|
34
|
-
pub const StringSlice = Slice([]String, [*]String);
|
|
35
|
-
pub const ConstStringSlice = Slice([]ConstString, [*]ConstString);
|
|
36
|
-
|
|
37
|
-
/// Slice of `StringPtr`s
|
|
38
|
-
pub const StringPtrSlice = Slice([]StringPtr, [*]StringPtr);
|
|
39
|
-
pub const ConstStringPtrSlice = Slice([]ConstStringPtr, [*]ConstStringPtr);
|
|
40
|
-
|
|
41
|
-
/// Alias for `*anyopaque`
|
|
42
|
-
pub const OpaquePtr = *anyopaque;
|
|
43
|
-
pub const ConstOpaquePtr = *const anyopaque;
|
|
44
|
-
|
|
45
|
-
/// Slice of `OpaquePtr`s
|
|
46
|
-
pub const OpaquePtrSlice = Slice([]OpaquePtr, [*]OpaquePtr);
|
|
47
|
-
pub const ConstOpaquePtrSlice = Slice([]ConstOpaquePtr, [*]ConstOpaquePtr);
|
|
48
|
-
|
|
49
|
-
/// Syntax sugar for `ConstString.wrap()`
|
|
50
|
-
pub inline fn string(str: []const u8) ConstString {
|
|
51
|
-
return ConstString.wrap(str);
|
|
52
|
-
}
|