@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # Change Log
2
2
 
3
- - **Last updated**: 2022-11-23T22:46:54Z
3
+ - **Last updated**: 2022-11-24T12:23:48Z
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.
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. Other languages require
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
- // Unique API module identifier to group WASM imports,
87
- // must match ID used by native code (see further below).
88
- readonly id = "custom";
89
- // optionally list IDs of other API modules this module depends on
90
- // these are used to infer the correct initialization order
91
- readonly dependencies = [];
92
-
93
- parent!: WasmBridge;
94
-
95
- async init(parent: WasmBridge) {
96
- this.parent = parent;
97
- this.parent.logger.debug("initializing custom API");
98
-
99
- // any other tasks you might need to do...
100
-
101
- return true;
102
- }
103
-
104
- /**
105
- * Returns object of functions to import as externals into the
106
- * WASM module during instantiation. These imports are merged
107
- * into a larger imports object alongside the bridge's core API...
108
- */
109
- getImports(): WebAssembly.Imports {
110
- return {
111
- /**
112
- * Writes `num` random float32 numbers from given address
113
- */
114
- fillRandom: (addr: number, num: number) => {
115
- addr >>>= 2;
116
- while(num-- > 0) this.parent.f32[addr++] = Math.random();
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
- var foo = [4]f32{ 1, 2, 3, 4 };
153
+ var foo = [4]f32{ 1, 2, 3, 4 };
155
154
 
156
- // print original
157
- js.printF32Array(foo[0..]);
155
+ // print original
156
+ js.printF32Array(foo[0..]);
158
157
 
159
- // populate foo with random numbers
160
- custom.fillRandom(&foo, foo.len);
158
+ // populate foo with random numbers
159
+ custom.fillRandom(&foo, foo.len);
161
160
 
162
- // print result
163
- js.printF32Array(foo[0..]);
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#L37-L71):
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#L20-L30):
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
- // allocate 256 bytes of memory for passing a string to WASM side
221
- // the function returns a tuple of `[address, len]`
222
- const [addr, len] = bridge.allocate(256);
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
- // write zero terminated string to reserved memory (max. `len` bytes)
225
- // function returns number of bytes written (excl. sentinel)
226
- const num = bridge.setString("hello WASM world!", addr, len, true);
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
- // call WASM function doing something w/ the string
229
- bridge.exports.doSomethingWithString(addr, num);
236
+ // call WASM function doing something w/ the string
237
+ bridge.exports.doSomethingWithString(addr, num);
230
238
 
231
- // cleanup
232
- bridge.free([addr, len]);
239
+ // cleanup
240
+ bridge.free([addr, len]);
233
241
  } catch(e) {
234
- // deal with allocation error
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-timer](https://github.com/thi-ng/umbrella/blob/develop/packages/wasm-api-timer/)
292
- modules this is used to manage Zig event listeners.
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
- start: () => void;
375
+ start: () => void;
368
376
  }
369
377
 
370
378
  (async () => {
371
- // new API bridge with defaults
372
- // (i.e. no child API modules and using console logger)
373
- const bridge = new WasmBridge<App>();
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
- // instantiate WASM module using imports provided by the bridge
376
- // this also initializes any bindings & bridge child APIs (if any)
377
- // (also accepts a fetch() `Response` as input)
378
- await bridge.instantiate(readFileSync("hello.wasm"));
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
- // call an exported WASM function
381
- bridge.exports.start();
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
- js.printStr("hello world!");
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
- --pkg-begin wasmapi node_modules/@thi.ng/wasm-api/zig/lib.zig --pkg-end \
413
- -target wasm32-freestanding \
414
- -O ReleaseSmall -dynamic --strip \
415
- hello.zig
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 WASM_KEEP start() {
458
- wasm_printStr0("hello world!");
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
@@ -1,7 +1,5 @@
1
1
  #pragma once
2
2
 
3
- #include "wasmapi_types.h"
4
-
5
3
  #ifdef __cplusplus
6
4
  extern "C" {
7
5
  #endif
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thi.ng/wasm-api",
3
- "version": "1.0.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": "044ee6a3895720fc78e115032d4d831b63510929\n"
113
+ "gitHead": "8d59e559a576ecb3d2c2d13edf5c3146df95d6ac\n"
114
114
  }
package/zig/lib.zig CHANGED
@@ -2,9 +2,6 @@
2
2
 
3
3
  const std = @import("std");
4
4
  const root = @import("root");
5
- const types = @import("types.zig");
6
-
7
- pub usingnamespace types;
8
5
 
9
6
  pub const ManagedIndex = @import("managed-index.zig").ManagedIndex;
10
7
 
@@ -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
- }