@thi.ng/wasm-api 0.6.0 → 0.9.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 +37 -1
- package/README.md +336 -39
- package/api.d.ts +91 -14
- package/bin/wasm-api +12 -0
- package/bridge.d.ts +4 -3
- package/bridge.js +6 -3
- package/cli.d.ts +5 -0
- package/cli.js +142 -0
- package/codegen/typescript.d.ts +13 -0
- package/codegen/typescript.js +65 -22
- package/codegen/utils.d.ts +29 -4
- package/codegen/utils.js +27 -4
- package/codegen/zig.d.ts +3 -0
- package/codegen/zig.js +5 -6
- package/codegen.d.ts +38 -1
- package/codegen.js +48 -16
- package/include/wasmapi.h +6 -0
- package/include/wasmapi.zig +6 -0
- package/index.d.ts +2 -2
- package/index.js +2 -2
- package/package.json +15 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
-
- **Last updated**: 2022-08-
|
|
3
|
+
- **Last updated**: 2022-08-23T10:37:04Z
|
|
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,42 @@ 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.9.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/wasm-api@0.9.0) (2022-08-23)
|
|
13
|
+
|
|
14
|
+
#### 🚀 Features
|
|
15
|
+
|
|
16
|
+
- add debug() core API function ([ca01978](https://github.com/thi-ng/umbrella/commit/ca01978))
|
|
17
|
+
|
|
18
|
+
#### 🩹 Bug fixes
|
|
19
|
+
|
|
20
|
+
- update setString() return value ([116dd0b](https://github.com/thi-ng/umbrella/commit/116dd0b))
|
|
21
|
+
- always only return num bytes written w/o sentinel
|
|
22
|
+
|
|
23
|
+
## [0.8.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/wasm-api@0.8.0) (2022-08-16)
|
|
24
|
+
|
|
25
|
+
#### 🚀 Features
|
|
26
|
+
|
|
27
|
+
- add preliminary string handling support ([3da4efe](https://github.com/thi-ng/umbrella/commit/3da4efe))
|
|
28
|
+
- update/rename IWasmMemoryAccess (add string getter/setter)
|
|
29
|
+
- update StructField.type (add `string`)
|
|
30
|
+
- add CodeGenOpts.stringType option
|
|
31
|
+
- update codegen fns
|
|
32
|
+
- update TS & Zig codegen impls
|
|
33
|
+
|
|
34
|
+
## [0.7.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/wasm-api@0.7.0) (2022-08-15)
|
|
35
|
+
|
|
36
|
+
#### 🚀 Features
|
|
37
|
+
|
|
38
|
+
- add CLI wrapper for codegens ([683a560](https://github.com/thi-ng/umbrella/commit/683a560))
|
|
39
|
+
- update TSOpts & TS codegen ([4f6bbbf](https://github.com/thi-ng/umbrella/commit/4f6bbbf))
|
|
40
|
+
- add `uppercaseEnum` option to force UC enum IDs
|
|
41
|
+
- update helper predicates ([65b23d4](https://github.com/thi-ng/umbrella/commit/65b23d4))
|
|
42
|
+
|
|
43
|
+
#### 🩹 Bug fixes
|
|
44
|
+
|
|
45
|
+
- allow signed ints for enum tags ([78d0822](https://github.com/thi-ng/umbrella/commit/78d0822))
|
|
46
|
+
- correct TS __mapArray codegen ([289b137](https://github.com/thi-ng/umbrella/commit/289b137))
|
|
47
|
+
|
|
12
48
|
## [0.6.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/wasm-api@0.6.0) (2022-08-15)
|
|
13
49
|
|
|
14
50
|
#### 🚀 Features
|
package/README.md
CHANGED
|
@@ -11,11 +11,13 @@ This project is part of the
|
|
|
11
11
|
|
|
12
12
|
- [About](#about)
|
|
13
13
|
- [Custom API modules](#custom-api-modules)
|
|
14
|
-
- [Object indices & handles](#object-indices--handles)
|
|
15
14
|
- [Data bindings & code generators](#data-bindings--code-generators)
|
|
15
|
+
- [CLI generator](#cli-generator)
|
|
16
16
|
- [Data type definitions](#data-type-definitions)
|
|
17
|
-
- [Code generation](#code-generation)
|
|
18
17
|
- [Example usage](#example-usage)
|
|
18
|
+
- [String handling](#string-handling)
|
|
19
|
+
- [Memory allocations](#memory-allocations)
|
|
20
|
+
- [Object indices & handles](#object-indices--handles)
|
|
19
21
|
- [Status](#status)
|
|
20
22
|
- [Installation](#installation)
|
|
21
23
|
- [Dependencies](#dependencies)
|
|
@@ -36,23 +38,31 @@ This package provides a the following:
|
|
|
36
38
|
[`WasmBridge`](https://docs.thi.ng/umbrella/wasm-api/classes/WasmBridge.html)
|
|
37
39
|
class as interop basis and much reduced boilerplate for hybrid JS/WebAssembly
|
|
38
40
|
applications.
|
|
39
|
-
2. A minimal core API for
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
4. Include files for C11 and Zig, defining imports for the JS core API defined
|
|
41
|
+
2. A minimal core API for memory allocation (can be disabled), debug output,
|
|
42
|
+
string/pointer/typedarray accessors for 8/16/32/64 bit (u)ints and 32/64 bit
|
|
43
|
+
floats. In the future we aim to also supply support modules for DOM
|
|
44
|
+
manipulation, WebGL, WebGPU, WebAudio etc.
|
|
45
|
+
3. [Include files for C11/C++ and
|
|
46
|
+
Zig](https://github.com/thi-ng/umbrella/tree/develop/packages/wasm-api/include),
|
|
47
|
+
defining WASM imports of the JS [core
|
|
48
|
+
API](https://docs.thi.ng/umbrella/wasm-api/interfaces/CoreAPI.html) defined
|
|
48
49
|
by this package
|
|
50
|
+
4. Extensible shared datatype code generators for (currently)
|
|
51
|
+
[Zig](https://ziglang.org) & TypeScript. The latter also generates fully type
|
|
52
|
+
checked memory-mapped (zero-copy) accessors of WASM-side data. In general,
|
|
53
|
+
all languages with a WebAssembly target are supported, however currently only
|
|
54
|
+
bindings for these few langs are included.
|
|
55
|
+
5. [CLI frontend/utility](#cli-generator) to invoke the code generator(s)
|
|
49
56
|
|
|
50
57
|
### Custom API modules
|
|
51
58
|
|
|
52
|
-
The
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
59
|
+
The
|
|
60
|
+
[`WasmBridge`](https://docs.thi.ng/umbrella/wasm-api/classes/WasmBridge.html) is
|
|
61
|
+
extensible via custom defined API modules. Such API extensions will consist of a
|
|
62
|
+
collection of JS/TS functions & variables, their related counterparts (import
|
|
63
|
+
definitions) for the WASM target and (optionally) some shared data types
|
|
64
|
+
([bindings for which _can_ be generated by this package
|
|
65
|
+
too](#data-bindings--code-generators)).
|
|
56
66
|
|
|
57
67
|
On the JS side, custom API modules can be easily integrated via the [`IWasmAPI`
|
|
58
68
|
interface](https://docs.thi.ng/umbrella/wasm-api/interfaces/IWasmAPI.html). The
|
|
@@ -127,6 +137,314 @@ export fn test_randomVec2() void {
|
|
|
127
137
|
}
|
|
128
138
|
```
|
|
129
139
|
|
|
140
|
+
### Data bindings & code generators
|
|
141
|
+
|
|
142
|
+
The package provides an extensible codegeneration framework to simplify the
|
|
143
|
+
bilateral design & exchange of data structures shared between the WASM & JS host
|
|
144
|
+
env. Currently, code generators for TypeScript & Zig are supplied (more are
|
|
145
|
+
planned). A CLI wrapper is worked on too.
|
|
146
|
+
|
|
147
|
+
#### CLI generator
|
|
148
|
+
|
|
149
|
+
The package includes a [small CLI
|
|
150
|
+
wrapper](https://github.com/thi-ng/umbrella/blob/develop/packages/wasm-api/src/cli.ts)
|
|
151
|
+
to invoke the codegenerator(s) from JSON type definitions and to write the
|
|
152
|
+
generated source code(s) to different files:
|
|
153
|
+
|
|
154
|
+
```text
|
|
155
|
+
$ npx @thi.ng/wasm-api
|
|
156
|
+
|
|
157
|
+
█ █ █ │
|
|
158
|
+
██ █ │
|
|
159
|
+
█ █ █ █ █ █ █ █ │ @thi.ng/wasm-api 0.6.0
|
|
160
|
+
█ █ █ █ █ █ █ █ █ │ Multi-language data bindings code generator
|
|
161
|
+
█ │
|
|
162
|
+
█ █ │
|
|
163
|
+
|
|
164
|
+
usage: wasm-api [OPTS] JSON-INPUT-FILE(S) ...
|
|
165
|
+
wasm-api --help
|
|
166
|
+
|
|
167
|
+
Flags:
|
|
168
|
+
|
|
169
|
+
-d, --debug enable debug output
|
|
170
|
+
--dry-run enable dry run (don't overwrite files)
|
|
171
|
+
|
|
172
|
+
Main:
|
|
173
|
+
|
|
174
|
+
-c FILE, --config FILE JSON config file with codegen options
|
|
175
|
+
-l ID[,..], --lang ID[,..] [multiple] target language: "ts", "zig" (default: ["ts","zig"])
|
|
176
|
+
-o FILE, --out FILE [multiple] output file path
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
By default, the CLI generates sources for both TypeScript and Zig (in this
|
|
180
|
+
order!). Order is important, since the output file paths must be given in the
|
|
181
|
+
same order as the target languages. It's recommended to be more explicit. An
|
|
182
|
+
example invocation looks like:
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
wasm-api --config codegen-opts.json \
|
|
186
|
+
--lang ts -o src/generated.ts \
|
|
187
|
+
--lang zig -o src.zig/generated.zig \
|
|
188
|
+
typedefs.json
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
The structure of the config file is as follows (all optional):
|
|
192
|
+
|
|
193
|
+
```text
|
|
194
|
+
{
|
|
195
|
+
global: { ... },
|
|
196
|
+
ts: { ... },
|
|
197
|
+
zig: { ... },
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
More details about possible
|
|
202
|
+
[`global`](https://docs.thi.ng/umbrella/wasm-api/interfaces/CodeGenOpts.html),
|
|
203
|
+
[`ts`](https://docs.thi.ng/umbrella/wasm-api/interfaces/TSOpts.html) and
|
|
204
|
+
[`zig`](https://docs.thi.ng/umbrella/wasm-api/interfaces/ZigOpts.html) config
|
|
205
|
+
options & values.
|
|
206
|
+
|
|
207
|
+
#### Data type definitions
|
|
208
|
+
|
|
209
|
+
Currently, the code generator supports structs and enums. See API docs for
|
|
210
|
+
further details:
|
|
211
|
+
|
|
212
|
+
- [`Enum`](https://docs.thi.ng/umbrella/wasm-api/interfaces/Enum.html)
|
|
213
|
+
- [`EnumValue`](https://docs.thi.ng/umbrella/wasm-api/interfaces/EnumValue.html)
|
|
214
|
+
- [`Struct`](https://docs.thi.ng/umbrella/wasm-api/interfaces/Struct.html)
|
|
215
|
+
- [`StructField`](https://docs.thi.ng/umbrella/wasm-api/interfaces/StructField.html)
|
|
216
|
+
- [`TopLevelType`](https://docs.thi.ng/umbrella/wasm-api/interfaces/TopLevelType.html)
|
|
217
|
+
|
|
218
|
+
#### Example usage
|
|
219
|
+
|
|
220
|
+
Below is an example file with JSON type definitions and the resulting source
|
|
221
|
+
codes:
|
|
222
|
+
|
|
223
|
+
**⬇︎ CLICK TO EXPAND EACH CODE BLOCK ⬇︎**
|
|
224
|
+
|
|
225
|
+
<details><summary>types.json (Type definitions)</summary>
|
|
226
|
+
|
|
227
|
+
```json
|
|
228
|
+
[
|
|
229
|
+
{
|
|
230
|
+
"name": "Foo",
|
|
231
|
+
"type": "struct",
|
|
232
|
+
"doc": "Example struct",
|
|
233
|
+
"auto": true,
|
|
234
|
+
"fields": [
|
|
235
|
+
{ "name": "id", "type": "u8", "doc": "Unique ID" },
|
|
236
|
+
{ "name": "bars", "type": "Bar", "tag": "array", "len": 3 },
|
|
237
|
+
{ "name": "color", "type": "f32", "tag": "vec", "len": 4 }
|
|
238
|
+
]
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
"name": "Bar",
|
|
242
|
+
"type": "struct",
|
|
243
|
+
"fields": [
|
|
244
|
+
{ "name": "kind", "type": "Kind" },
|
|
245
|
+
{ "name": "flags", "type": "u32" }
|
|
246
|
+
]
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
"name": "Kind",
|
|
250
|
+
"type": "enum",
|
|
251
|
+
"tag": "u16",
|
|
252
|
+
"values": [
|
|
253
|
+
"unknown",
|
|
254
|
+
{ "name": "good", "value": 100 },
|
|
255
|
+
{ "name": "best", "value": 1000 }
|
|
256
|
+
]
|
|
257
|
+
}
|
|
258
|
+
]
|
|
259
|
+
```
|
|
260
|
+
</details>
|
|
261
|
+
|
|
262
|
+
<details><summary>generated.ts (generated TypeScript source)</summary>
|
|
263
|
+
|
|
264
|
+
```ts
|
|
265
|
+
/** Generated by @thi.ng/wasm-api at 2022-08-15T22:32:21.189Z - DO NOT EDIT! */
|
|
266
|
+
|
|
267
|
+
import type { WasmTypeBase, WasmTypeConstructor } from "@thi.ng/wasm-api";
|
|
268
|
+
|
|
269
|
+
/** Example struct */
|
|
270
|
+
export interface Foo extends WasmTypeBase {
|
|
271
|
+
color: Float32Array;
|
|
272
|
+
bars: Bar[];
|
|
273
|
+
/** Unique ID */
|
|
274
|
+
id: number;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
export const $Foo: WasmTypeConstructor<Foo> = (mem) => ({
|
|
278
|
+
get align() { return 16; },
|
|
279
|
+
get size() { return 48; },
|
|
280
|
+
instance: (base) => ({
|
|
281
|
+
get __base() { return base; },
|
|
282
|
+
get __bytes() { return mem.u8.subarray(base, base + 48); },
|
|
283
|
+
get color(): Float32Array {
|
|
284
|
+
const addr = base >>> 2;
|
|
285
|
+
return mem.f32.subarray(addr, addr + 4);
|
|
286
|
+
},
|
|
287
|
+
get bars(): Bar[] {
|
|
288
|
+
const addr = (base + 16);
|
|
289
|
+
const inst = $Bar(mem);
|
|
290
|
+
const slice: Bar[] = [];
|
|
291
|
+
for(let i = 0; i < 3; i++) slice.push(inst.instance(addr + i * 24));
|
|
292
|
+
return slice;
|
|
293
|
+
},
|
|
294
|
+
get id(): number {
|
|
295
|
+
return mem.u8[(base + 40)];
|
|
296
|
+
},
|
|
297
|
+
set id(x: number) {
|
|
298
|
+
mem.u8[(base + 40)] = x;
|
|
299
|
+
},
|
|
300
|
+
})
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
export interface Bar extends WasmTypeBase {
|
|
304
|
+
kind: Kind;
|
|
305
|
+
flags: number;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
export const $Bar: WasmTypeConstructor<Bar> = (mem) => ({
|
|
309
|
+
get align() { return 4; },
|
|
310
|
+
get size() { return 8; },
|
|
311
|
+
instance: (base) => ({
|
|
312
|
+
get __base() { return base; },
|
|
313
|
+
get __bytes() { return mem.u8.subarray(base, base + 8); },
|
|
314
|
+
get kind(): Kind {
|
|
315
|
+
return mem.u16[base >>> 1];
|
|
316
|
+
},
|
|
317
|
+
set kind(x: Kind) {
|
|
318
|
+
mem.u16[base >>> 1] = x;
|
|
319
|
+
},
|
|
320
|
+
get flags(): number {
|
|
321
|
+
return mem.u32[(base + 4) >>> 2];
|
|
322
|
+
},
|
|
323
|
+
set flags(x: number) {
|
|
324
|
+
mem.u32[(base + 4) >>> 2] = x;
|
|
325
|
+
},
|
|
326
|
+
})
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
export enum Kind {
|
|
330
|
+
UNKNOWN,
|
|
331
|
+
GOOD = 100,
|
|
332
|
+
BEST = 1000,
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
</details>
|
|
336
|
+
|
|
337
|
+
<details><summary>generated.zig (generated Zig source)</summary>
|
|
338
|
+
|
|
339
|
+
```zig
|
|
340
|
+
//! Generated by @thi.ng/wasm-api at 2022-08-15T22:32:21.191Z - DO NOT EDIT!
|
|
341
|
+
|
|
342
|
+
/// Example struct
|
|
343
|
+
pub const Foo = struct {
|
|
344
|
+
color: @Vector(4, f32),
|
|
345
|
+
bars: [3]Bar,
|
|
346
|
+
/// Unique ID
|
|
347
|
+
id: u8,
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
pub const Bar = struct {
|
|
351
|
+
kind: Kind,
|
|
352
|
+
flags: u32,
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
pub const Kind = enum(u16) {
|
|
356
|
+
unknown,
|
|
357
|
+
good = 100,
|
|
358
|
+
best = 1000,
|
|
359
|
+
};
|
|
360
|
+
```
|
|
361
|
+
</details>
|
|
362
|
+
|
|
363
|
+
On the TypeScript/JS side, the memory-mapped wrappers (e.g. `$Foo` and `$Bar`)
|
|
364
|
+
can be used in combination with the `WasmBridge` to obtain fully typed views
|
|
365
|
+
(according to the generated types) of the underlying WASM memory. Basic usage is
|
|
366
|
+
like:
|
|
367
|
+
|
|
368
|
+
```ts
|
|
369
|
+
import { WasmBridge } from "@thi.ng/wasm-api";
|
|
370
|
+
import { $Foo, Kind } from "./generated.ts";
|
|
371
|
+
|
|
372
|
+
const bridge = new WasmBridge();
|
|
373
|
+
// bridge initialization omitted here (see other examples below)
|
|
374
|
+
// ...
|
|
375
|
+
|
|
376
|
+
// Create an instance using the bridge's memory views
|
|
377
|
+
// and mapping a `Foo` struct from given address
|
|
378
|
+
// (e.g. obtained from an exported WASM function/value)
|
|
379
|
+
const foo = $Foo(bridge).instance(0x10000);
|
|
380
|
+
|
|
381
|
+
// then use like normal JS object
|
|
382
|
+
foo.color
|
|
383
|
+
// Float32Array(4) [0.1, 0.2, 0.3, 0.4]
|
|
384
|
+
|
|
385
|
+
// this even applies to arrays using other types
|
|
386
|
+
foo.bars[2].kind = Kind.BEST;
|
|
387
|
+
|
|
388
|
+
// IMPORTANT: any modifications like this are directly
|
|
389
|
+
// applied to the underlying WASM memory...
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
**IMPORTANT:** Struct field setters are currently only supported for single
|
|
393
|
+
values, incl. enums, strings, structs. The latter 2 will always be copied by
|
|
394
|
+
value (mem copy). Arrays or slices of strings do not currently provide write
|
|
395
|
+
access...
|
|
396
|
+
|
|
397
|
+
### String handling
|
|
398
|
+
|
|
399
|
+
Most low-level languages deal with strings very differently and alas there's no
|
|
400
|
+
general standard. Some have UTF-8/16 support, others don't. In some languages
|
|
401
|
+
(incl. C & Zig), strings are stored as zero terminated, in others they aren't...
|
|
402
|
+
It's outside the scope of this package to provide an allround out-of-the-box
|
|
403
|
+
solution. The `WasmBridge` provides read & write accessors to obtain JS strings
|
|
404
|
+
from UTF-8 encoded WASM memory. See
|
|
405
|
+
[`getString()`](https://docs.thi.ng/umbrella/wasm-api/classes/WasmBridge.html#getString)
|
|
406
|
+
and
|
|
407
|
+
[`setString()`](https://docs.thi.ng/umbrella/wasm-api/classes/WasmBridge.html#setString)
|
|
408
|
+
for details.
|
|
409
|
+
|
|
410
|
+
The code generators too provide a global `stringType` option to
|
|
411
|
+
interpret the `string` type of a struct field in different ways:
|
|
412
|
+
|
|
413
|
+
- `slice` (default): Considers strings as Zig-style slices (i.e. pointer + length)
|
|
414
|
+
- `ptr`: Considers strings as C-style raw `*char` pointer (without any length)
|
|
415
|
+
|
|
416
|
+
Note: If setting this global option to `ptr`, it also has to be repeated for the
|
|
417
|
+
TypeScript code generator explicitly.
|
|
418
|
+
|
|
419
|
+
### Memory allocations
|
|
420
|
+
|
|
421
|
+
The `WasmBridge` includes support for malloc/free-style allocations (within the
|
|
422
|
+
linear WASM memory), _unless_ these are explicitly disabled on the WASM side. Please see for further reference:
|
|
423
|
+
|
|
424
|
+
- [`/include/wasmapi.zig`](https://github.com/thi-ng/umbrella/blob/develop/packages/wasm-api/include/wasmapi.zig#L6) - comments about WASM-side allocator handling
|
|
425
|
+
- [`WasmBridge.allocate()`](https://docs.thi.ng/umbrella/wasm-api/classes/WasmBridge.html#allocate) - allocating memory from JS side
|
|
426
|
+
- [`WasmBridge.free()`](https://docs.thi.ng/umbrella/wasm-api/classes/WasmBridge.html#free) - freeing previously allocated memory
|
|
427
|
+
|
|
428
|
+
```ts
|
|
429
|
+
try {
|
|
430
|
+
// allocate 1KB of memory for passing a string to WASM side
|
|
431
|
+
const addr = bridge.allocate(256);
|
|
432
|
+
|
|
433
|
+
// write string to reserved memory
|
|
434
|
+
// max. 256 bytes written, zero terminated
|
|
435
|
+
const num = bridge.setString("hello WASM world!", addr, 256, true);
|
|
436
|
+
|
|
437
|
+
// call WASM function doing something w/ the string
|
|
438
|
+
bridge.exports.doSomethingWithString(addr, num);
|
|
439
|
+
|
|
440
|
+
// cleanup
|
|
441
|
+
bridge.free(addr, 256);
|
|
442
|
+
} catch(e) {
|
|
443
|
+
// allocation error
|
|
444
|
+
// ...
|
|
445
|
+
}
|
|
446
|
+
```
|
|
447
|
+
|
|
130
448
|
### Object indices & handles
|
|
131
449
|
|
|
132
450
|
Since only numeric values can be exchanged between the WASM module and the JS
|
|
@@ -174,29 +492,6 @@ canvases.delete(0);
|
|
|
174
492
|
// true
|
|
175
493
|
```
|
|
176
494
|
|
|
177
|
-
### Data bindings & code generators
|
|
178
|
-
|
|
179
|
-
The package provides an extensible codegeneration framework to simplify the
|
|
180
|
-
bilateral design & exchange of data structures shared between the WASM & JS host
|
|
181
|
-
env. Currently, code generators for TypeScript & Zig are supplied (more are
|
|
182
|
-
planned). A CLI wrapper is worked on too.
|
|
183
|
-
|
|
184
|
-
#### Data type definitions
|
|
185
|
-
|
|
186
|
-
TODO
|
|
187
|
-
|
|
188
|
-
##### Struct
|
|
189
|
-
|
|
190
|
-
##### Enum
|
|
191
|
-
|
|
192
|
-
#### Code generation
|
|
193
|
-
|
|
194
|
-
TODO
|
|
195
|
-
|
|
196
|
-
#### Example usage
|
|
197
|
-
|
|
198
|
-
TODO
|
|
199
|
-
|
|
200
495
|
### Status
|
|
201
496
|
|
|
202
497
|
**ALPHA** - bleeding edge / work-in-progress
|
|
@@ -226,7 +521,7 @@ node --experimental-repl-await
|
|
|
226
521
|
> const wasmApi = await import("@thi.ng/wasm-api");
|
|
227
522
|
```
|
|
228
523
|
|
|
229
|
-
Package sizes (gzipped, pre-treeshake): ESM:
|
|
524
|
+
Package sizes (gzipped, pre-treeshake): ESM: 4.34 KB
|
|
230
525
|
|
|
231
526
|
**IMPORTANT:** The package includes various code generators and supporting
|
|
232
527
|
functions which are NOT required during runtime. Hence the actual package size
|
|
@@ -235,11 +530,13 @@ in production will be MUCH smaller!
|
|
|
235
530
|
## Dependencies
|
|
236
531
|
|
|
237
532
|
- [@thi.ng/api](https://github.com/thi-ng/umbrella/tree/develop/packages/api)
|
|
533
|
+
- [@thi.ng/args](https://github.com/thi-ng/umbrella/tree/develop/packages/args)
|
|
238
534
|
- [@thi.ng/binary](https://github.com/thi-ng/umbrella/tree/develop/packages/binary)
|
|
239
535
|
- [@thi.ng/checks](https://github.com/thi-ng/umbrella/tree/develop/packages/checks)
|
|
240
536
|
- [@thi.ng/compare](https://github.com/thi-ng/umbrella/tree/develop/packages/compare)
|
|
241
537
|
- [@thi.ng/defmulti](https://github.com/thi-ng/umbrella/tree/develop/packages/defmulti)
|
|
242
538
|
- [@thi.ng/errors](https://github.com/thi-ng/umbrella/tree/develop/packages/errors)
|
|
539
|
+
- [@thi.ng/file-io](https://github.com/thi-ng/umbrella/tree/develop/packages/file-io)
|
|
243
540
|
- [@thi.ng/hex](https://github.com/thi-ng/umbrella/tree/develop/packages/hex)
|
|
244
541
|
- [@thi.ng/idgen](https://github.com/thi-ng/umbrella/tree/develop/packages/idgen)
|
|
245
542
|
- [@thi.ng/logger](https://github.com/thi-ng/umbrella/tree/develop/packages/logger)
|
package/api.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FloatType, Fn, Fn2 } from "@thi.ng/api";
|
|
1
|
+
import type { BigType, FloatType, Fn, Fn2 } from "@thi.ng/api";
|
|
2
2
|
import type { WasmBridge } from "./bridge.js";
|
|
3
3
|
export declare const PKG_NAME = "@thi.ng/wasm-api";
|
|
4
4
|
export declare type BigIntArray = bigint[] | BigInt64Array | BigUint64Array;
|
|
@@ -66,7 +66,7 @@ export interface WasmExports {
|
|
|
66
66
|
*/
|
|
67
67
|
_wasm_free(addr: number, numBytes: number): void;
|
|
68
68
|
}
|
|
69
|
-
export interface
|
|
69
|
+
export interface IWasmMemoryAccess {
|
|
70
70
|
i8: Int8Array;
|
|
71
71
|
u8: Uint8Array;
|
|
72
72
|
i16: Int16Array;
|
|
@@ -77,6 +77,31 @@ export interface WasmMemViews {
|
|
|
77
77
|
u64: BigUint64Array;
|
|
78
78
|
f32: Float32Array;
|
|
79
79
|
f64: Float64Array;
|
|
80
|
+
/**
|
|
81
|
+
* Reads UTF-8 encoded string from given address and optional byte length.
|
|
82
|
+
* The default length is 0, which will be interpreted as a zero-terminated
|
|
83
|
+
* string. Returns string.
|
|
84
|
+
*
|
|
85
|
+
* @param addr
|
|
86
|
+
* @param len
|
|
87
|
+
*/
|
|
88
|
+
getString(addr: number, len?: number): string;
|
|
89
|
+
/**
|
|
90
|
+
* Encodes given string as UTF-8 and writes it to WASM memory starting at
|
|
91
|
+
* `addr`. By default the string will be zero-terminated and only `maxBytes`
|
|
92
|
+
* will be written. Returns the number of bytes written.
|
|
93
|
+
*
|
|
94
|
+
* @remarks
|
|
95
|
+
* An error will be thrown if the encoded string doesn't fully fit into the
|
|
96
|
+
* designated memory region (also note that there might need to be space for
|
|
97
|
+
* the additional sentinel/termination byte).
|
|
98
|
+
*
|
|
99
|
+
* @param str
|
|
100
|
+
* @param addr
|
|
101
|
+
* @param maxBytes
|
|
102
|
+
* @param terminate
|
|
103
|
+
*/
|
|
104
|
+
setString(str: string, addr: number, maxBytes: number, terminate?: boolean): number;
|
|
80
105
|
}
|
|
81
106
|
/**
|
|
82
107
|
* Core API of WASM imports defined by the {@link WasmBridge}. The same
|
|
@@ -110,6 +135,7 @@ export interface CoreAPI extends WebAssembly.ModuleImports {
|
|
|
110
135
|
_printF64Array: (addr: number, len: number) => void;
|
|
111
136
|
_printStr0: (addr: number) => void;
|
|
112
137
|
_printStr: (addr: number, len: number) => void;
|
|
138
|
+
debug: () => void;
|
|
113
139
|
}
|
|
114
140
|
export interface WasmTypeBase {
|
|
115
141
|
/**
|
|
@@ -126,11 +152,12 @@ export interface WasmType<T> {
|
|
|
126
152
|
readonly size: number;
|
|
127
153
|
instance: Fn<number, T>;
|
|
128
154
|
}
|
|
129
|
-
export declare type WasmTypeConstructor<T> = Fn<
|
|
155
|
+
export declare type WasmTypeConstructor<T> = Fn<IWasmMemoryAccess, WasmType<T>>;
|
|
130
156
|
export declare type WasmInt = "i8" | "i16" | "i32" | "i64";
|
|
131
157
|
export declare type WasmUint = "u8" | "u16" | "u32" | "u64";
|
|
132
158
|
export declare type WasmFloat = FloatType;
|
|
133
159
|
export declare type WasmPrim = WasmInt | WasmUint | WasmFloat;
|
|
160
|
+
export declare type WasmPrim32 = Exclude<WasmPrim, BigType>;
|
|
134
161
|
export declare type TypeColl = Record<string, TopLevelType>;
|
|
135
162
|
export interface TypeInfo {
|
|
136
163
|
/**
|
|
@@ -153,16 +180,30 @@ export interface TypeInfo {
|
|
|
153
180
|
__align?: number;
|
|
154
181
|
}
|
|
155
182
|
export interface TopLevelType extends TypeInfo {
|
|
183
|
+
/**
|
|
184
|
+
* Type name
|
|
185
|
+
*/
|
|
156
186
|
name: string;
|
|
187
|
+
/**
|
|
188
|
+
* Optional (multi-line) docstring for this type
|
|
189
|
+
*/
|
|
157
190
|
doc?: string;
|
|
191
|
+
/**
|
|
192
|
+
* Type / kind
|
|
193
|
+
*/
|
|
158
194
|
type: "struct" | "enum";
|
|
159
195
|
}
|
|
160
196
|
export interface Struct extends TopLevelType {
|
|
161
197
|
type: "struct";
|
|
198
|
+
/**
|
|
199
|
+
* List of struct fields (might be re-ordered if {@link Struct.auto} is
|
|
200
|
+
* enabled).
|
|
201
|
+
*/
|
|
162
202
|
fields: StructField[];
|
|
163
203
|
/**
|
|
164
204
|
* If true, struct fields will be re-ordered in descending order based on
|
|
165
|
-
* their {@link TypeInfo.__align} size.
|
|
205
|
+
* their {@link TypeInfo.__align} size. This might result in overall smaller
|
|
206
|
+
* structs due to minimizing inter-field padding.
|
|
166
207
|
*
|
|
167
208
|
* @defaultValue false
|
|
168
209
|
*/
|
|
@@ -178,43 +219,70 @@ export interface StructField extends TypeInfo {
|
|
|
178
219
|
*/
|
|
179
220
|
doc?: string;
|
|
180
221
|
/**
|
|
181
|
-
* Field type tag/qualifier (note: `slice` & `vec` are only supported by
|
|
182
|
-
*
|
|
222
|
+
* Field type tag/qualifier (note: `slice` & `vec` are only supported by Zig
|
|
223
|
+
* & TS).
|
|
224
|
+
*
|
|
225
|
+
* @remarks
|
|
226
|
+
* - Array & vector fields are statically sized (using
|
|
227
|
+
* {@link StructField.len})
|
|
228
|
+
* - Pointers are emitted as single-value pointers (where this distinction
|
|
229
|
+
* exist), i.e. even if they're pointing to multiple values, there's no
|
|
230
|
+
* explicit length encoded/available
|
|
231
|
+
* - Zig slices are essentially a pointer w/ associated length
|
|
232
|
+
* - Zig vectors will be processed using SIMD (if enabled in WASM target)
|
|
233
|
+
* and therefore will have stricter (larger) alignment requirements.
|
|
183
234
|
*
|
|
184
235
|
* @defaultValue "scalar"
|
|
185
236
|
*/
|
|
186
237
|
tag?: "scalar" | "array" | "ptr" | "slice" | "vec";
|
|
187
238
|
/**
|
|
188
|
-
* Field base type. If not a {@link WasmPrim} or `opaque`, the
|
|
189
|
-
* interpreted as another type name in the {@link TypeColl}.
|
|
239
|
+
* Field base type. If not a {@link WasmPrim}, `string` or `opaque`, the
|
|
240
|
+
* value is interpreted as another type name in the {@link TypeColl}.
|
|
241
|
+
*
|
|
242
|
+
* @remarks
|
|
243
|
+
* Please see {@link CodeGenOpts.stringType} and consult package readme for
|
|
244
|
+
* further details re: string handling.
|
|
190
245
|
*
|
|
191
246
|
* TODO `opaque` currently unsupported.
|
|
192
247
|
*/
|
|
193
|
-
type: WasmPrim | "opaque" | string;
|
|
248
|
+
type: WasmPrim | "string" | "opaque" | string;
|
|
194
249
|
/**
|
|
195
|
-
* TODO currently unsupported!
|
|
250
|
+
* TODO currently unsupported & ignored!
|
|
196
251
|
*/
|
|
197
252
|
sentinel?: number;
|
|
198
253
|
/**
|
|
199
|
-
* Array or vector length
|
|
254
|
+
* Array or vector length (see {@link StructField.tag})
|
|
200
255
|
*/
|
|
201
256
|
len?: number;
|
|
202
257
|
/**
|
|
203
|
-
* TODO currently unsupported!
|
|
258
|
+
* TODO currently unsupported & ignored!
|
|
204
259
|
*/
|
|
205
260
|
default?: any;
|
|
206
261
|
}
|
|
207
262
|
export interface Enum extends TopLevelType {
|
|
208
263
|
type: "enum";
|
|
209
264
|
/**
|
|
210
|
-
* No u64 support, due to Typescript not supporting bigint enum values
|
|
265
|
+
* No i64/u64 support, due to Typescript not supporting bigint enum values
|
|
266
|
+
*/
|
|
267
|
+
tag: Exclude<WasmPrim32, FloatType>;
|
|
268
|
+
/**
|
|
269
|
+
* List of possible values/IDs. Use {@link EnumValue}s for more detailed
|
|
270
|
+
* config.
|
|
211
271
|
*/
|
|
212
|
-
tag: Exclude<WasmUint, "u64">;
|
|
213
272
|
values: (string | EnumValue)[];
|
|
214
273
|
}
|
|
215
274
|
export interface EnumValue {
|
|
275
|
+
/**
|
|
276
|
+
* Enum value name/ID
|
|
277
|
+
*/
|
|
216
278
|
name: string;
|
|
279
|
+
/**
|
|
280
|
+
* Optional associated numeric value
|
|
281
|
+
*/
|
|
217
282
|
value?: number;
|
|
283
|
+
/**
|
|
284
|
+
* Optional docstring for this value
|
|
285
|
+
*/
|
|
218
286
|
doc?: string;
|
|
219
287
|
}
|
|
220
288
|
export interface ICodeGen {
|
|
@@ -226,8 +294,17 @@ export interface ICodeGen {
|
|
|
226
294
|
* Optional source code to be appended after any generated type defs.
|
|
227
295
|
*/
|
|
228
296
|
post?: string;
|
|
297
|
+
/**
|
|
298
|
+
* Docstring codegen
|
|
299
|
+
*/
|
|
229
300
|
doc: (doc: string, indent: string, acc: string[], topLevel?: boolean) => void;
|
|
301
|
+
/**
|
|
302
|
+
* Codegen for enum types.
|
|
303
|
+
*/
|
|
230
304
|
enum: (type: Enum, types: TypeColl, acc: string[]) => void;
|
|
305
|
+
/**
|
|
306
|
+
* Codegen for struct types.
|
|
307
|
+
*/
|
|
231
308
|
struct: (type: Struct, types: TypeColl, acc: string[]) => void;
|
|
232
309
|
}
|
|
233
310
|
/**
|
package/bin/wasm-api
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
# https://stackoverflow.com/a/246128/294515
|
|
4
|
+
SOURCE="${BASH_SOURCE[0]}"
|
|
5
|
+
while [ -h "$SOURCE" ]; do
|
|
6
|
+
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"
|
|
7
|
+
SOURCE="$(readlink "$SOURCE")"
|
|
8
|
+
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE"
|
|
9
|
+
done
|
|
10
|
+
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"
|
|
11
|
+
|
|
12
|
+
/usr/bin/env node "$DIR/../cli.js" "$DIR" "$@"
|