@thi.ng/wasm-api 0.15.0 → 0.16.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # Change Log
2
2
 
3
- - **Last updated**: 2022-10-26T12:46:53Z
3
+ - **Last updated**: 2022-10-28T19:08:39Z
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,30 @@ 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.16.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/wasm-api@0.16.0) (2022-10-28)
13
+
14
+ #### 🚀 Features
15
+
16
+ - update TS docstring generator ([5a060b6](https://github.com/thi-ng/umbrella/commit/5a060b6))
17
+ - include native/WASM type in docstring (use Zig type sigs)
18
+ - update ensureLines() helper
19
+ - update test fixtures
20
+ - update IWasmMemoryAccess & impls ([bb8a3ca](https://github.com/thi-ng/umbrella/commit/bb8a3ca))
21
+ - add MemorySlice tuple to describe a memory region
22
+ - update allocate() & free() to use MemorySlice, migrate to IWasmMemoryAccess
23
+ - migrate growMemory() to IWasmMemoryAccess
24
+ - add MemorySlice to default imports in TS codegen
25
+ - update docstring & user code codegen config ([68694ba](https://github.com/thi-ng/umbrella/commit/68694ba))
26
+ - allow doc strings & user codes to be given as string array (lines)
27
+ - add InjectedBody type to support multiple injection sites
28
+ (e.g. TS interface declarations vs. wrapper impls)
29
+ - update TS & Zig codegens
30
+ - add internal ensureLines() helper
31
+
32
+ #### 🩹 Bug fixes
33
+
34
+ - fix ensureLines(), update tests & fixtures ([f8a4668](https://github.com/thi-ng/umbrella/commit/f8a4668))
35
+
12
36
  ## [0.15.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/wasm-api@0.15.0) (2022-10-26)
13
37
 
14
38
  #### 🚀 Features
package/api.d.ts CHANGED
@@ -53,7 +53,7 @@ export interface WasmExports {
53
53
  * @remarks
54
54
  * #### Zig
55
55
  *
56
- * Using the supplied Zig bindings (see `/include/wasmapi.zig`), it's the
56
+ * Using the supplied Zig bindings (see `/zig/wasmapi.zig`), it's the
57
57
  * user's responsibility to define a public `WASM_ALLOCATOR` in the root
58
58
  * source file to enable allocations, e.g. using the
59
59
  * [`std.heap.GeneralPurposeAllocator`](https://ziglang.org/documentation/master/#Choosing-an-Allocator)
@@ -81,6 +81,7 @@ export interface WasmExports {
81
81
  */
82
82
  _wasm_free(addr: number, numBytes: number): void;
83
83
  }
84
+ export declare type MemorySlice = [addr: number, len: number];
84
85
  export interface IWasmMemoryAccess {
85
86
  i8: Int8Array;
86
87
  u8: Uint8Array;
@@ -97,6 +98,41 @@ export interface IWasmMemoryAccess {
97
98
  * after growing the WASM memory and the previous buffer becoming detached).
98
99
  */
99
100
  ensureMemory(): void;
101
+ /**
102
+ * Attempts to grow the WASM memory by an additional `numPages` (64KB/page)
103
+ * and if successful updates all typed memory views to use the new
104
+ * underlying buffer.
105
+ *
106
+ * @param numPages
107
+ */
108
+ growMemory(numPages: number): void;
109
+ /**
110
+ * Attempts to allocate `numBytes` using the exported WASM core API function
111
+ * {@link WasmExports._wasm_allocate} (implementation specific) and returns
112
+ * start address of the new memory block. If unsuccessful, throws an
113
+ * {@link OutOfMemoryError}. If `clear` is true, the allocated region will
114
+ * be zero-filled.
115
+ *
116
+ * @remarks
117
+ * See {@link WasmExports._wasm_allocate} docs for further details.
118
+ *
119
+ * @param numBytes
120
+ * @param clear
121
+ */
122
+ allocate(numBytes: number, clear?: boolean): MemorySlice;
123
+ /**
124
+ * Frees a previous allocated memory region using the exported WASM core API
125
+ * function {@link WasmExports._wasm_free} (implementation specific). The
126
+ * `numBytes` value must be the same as previously given to
127
+ * {@link IWasmMemoryAccess.allocate}.
128
+ *
129
+ * @remarks
130
+ * This function always succeeds, regardless of presence of an active
131
+ * allocator on the WASM side or validity of given arguments.
132
+ *
133
+ * @param slice
134
+ */
135
+ free(slice: MemorySlice): void;
100
136
  /**
101
137
  * Reads UTF-8 encoded string from given address and optional byte length.
102
138
  * The default length is 0, which will be interpreted as a zero-terminated
@@ -217,19 +253,24 @@ export interface TopLevelType extends TypeInfo {
217
253
  /**
218
254
  * Optional (multi-line) docstring for this type
219
255
  */
220
- doc?: string;
256
+ doc?: string | string[];
221
257
  /**
222
258
  * Type / kind
223
259
  */
224
260
  type: "enum" | "struct" | "union";
225
261
  /**
226
262
  * Optional object of user provided source codes to be injected into the
227
- * generated type. Keys are language IDs (same name as respective codegen).
263
+ * generated type (after generated fields). Keys of this object are language
264
+ * IDs (`ts` for {@link TYPESCRIPT}, `zig` for {@link ZIG}).
228
265
  *
229
266
  * @remarks
230
- * Currently only supported by the {@link ZIG} codegen, ignored otherwise.
267
+ * Currently only supported by the code gens mentioned, ignored otherwise.
231
268
  */
232
- body?: IObjectOf<string>;
269
+ body?: IObjectOf<string | string[] | InjectedBody>;
270
+ }
271
+ export interface InjectedBody {
272
+ decl?: string | string[];
273
+ impl?: string | string[];
233
274
  }
234
275
  export interface Struct extends TopLevelType {
235
276
  type: "struct";
@@ -259,6 +300,23 @@ export interface Struct extends TopLevelType {
259
300
  */
260
301
  align?: AlignStrategy;
261
302
  }
303
+ export interface Union extends TopLevelType {
304
+ type: "union";
305
+ /**
306
+ * Array of union fields.
307
+ */
308
+ fields: Field[];
309
+ /**
310
+ * Optional qualifier for the kind of struct to be emitted (codegen specific
311
+ * interpretation, currently only used by {@link ZIG}).
312
+ */
313
+ tag?: "extern" | "packed";
314
+ /**
315
+ * Optional user supplied {@link AlignStrategy}. By default uses
316
+ * {@link ALIGN_C} or {@link ALIGN_PACKED} (if using "packed" union).
317
+ */
318
+ align?: AlignStrategy;
319
+ }
262
320
  export declare type FieldTag = "scalar" | "array" | "ptr" | "slice" | "vec";
263
321
  export interface Field extends TypeInfo {
264
322
  /**
@@ -268,7 +326,7 @@ export interface Field extends TypeInfo {
268
326
  /**
269
327
  * Field docstring (can be multiline, will be formatted)
270
328
  */
271
- doc?: string;
329
+ doc?: string | string[];
272
330
  /**
273
331
  * Field type tag/qualifier (note: `slice` & `vec` are only supported by Zig
274
332
  * & TS).
@@ -323,23 +381,6 @@ export interface Field extends TypeInfo {
323
381
  */
324
382
  pad?: number;
325
383
  }
326
- export interface Union extends TopLevelType {
327
- type: "union";
328
- /**
329
- * Array of union fields.
330
- */
331
- fields: Field[];
332
- /**
333
- * Optional qualifier for the kind of struct to be emitted (codegen specific
334
- * interpretation, currently only used by {@link ZIG}).
335
- */
336
- tag?: "extern" | "packed";
337
- /**
338
- * Optional user supplied {@link AlignStrategy}. By default uses
339
- * {@link ALIGN_C} or {@link ALIGN_PACKED} (if using "packed" union).
340
- */
341
- align?: AlignStrategy;
342
- }
343
384
  export interface Enum extends TopLevelType {
344
385
  type: "enum";
345
386
  /**
@@ -449,7 +490,7 @@ export interface ICodeGen {
449
490
  /**
450
491
  * Docstring codegen
451
492
  */
452
- doc: (doc: string, acc: string[], opts: CodeGenOpts, topLevel?: boolean) => void;
493
+ doc: (doc: string | string[], acc: string[], opts: CodeGenOpts, topLevel?: boolean) => void;
453
494
  /**
454
495
  * Codegen for enum types.
455
496
  */
package/bridge.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /// <reference types="node" />
2
2
  import type { Event, INotify, Listener, NumericArray } from "@thi.ng/api";
3
3
  import type { ILogger } from "@thi.ng/logger";
4
- import { BigIntArray, CoreAPI, IWasmAPI, IWasmMemoryAccess, WasmExports } from "./api.js";
4
+ import { BigIntArray, CoreAPI, IWasmAPI, IWasmMemoryAccess, MemorySlice, WasmExports } from "./api.js";
5
5
  export declare const Panic: {
6
6
  new (msg?: string | undefined): {
7
7
  name: string;
@@ -136,34 +136,8 @@ export declare class WasmBridge<T extends WasmExports = WasmExports> implements
136
136
  * @param numPages
137
137
  */
138
138
  growMemory(numPages: number): void;
139
- /**
140
- * Attempts to allocate `numBytes` using the exported WASM core API function
141
- * {@link WasmExports._wasm_allocate} (implementation specific) and returns
142
- * start address of the new memory block. If unsuccessful, throws an
143
- * {@link OutOfMemoryError}. If `clear` is true, the allocated region will
144
- * be zero-filled.
145
- *
146
- * @remarks
147
- * See {@link WasmExports._wasm_allocate} docs for further details.
148
- *
149
- * @param numBytes
150
- * @param clear
151
- */
152
- allocate(numBytes: number, clear?: boolean): number;
153
- /**
154
- * Frees a previous allocated memory region using the exported WASM core API
155
- * function {@link WasmExports._wasm_free} (implementation specific). The
156
- * `numBytes` value must be the same as previously given to
157
- * {@link WasmBridge.allocate}.
158
- *
159
- * @remarks
160
- * This function always succeeds, regardless of presence of an active
161
- * allocator on the WASM side or validity of given arguments.
162
- *
163
- * @param addr
164
- * @param numBytes
165
- */
166
- free(addr: number, numBytes: number): void;
139
+ allocate(numBytes: number, clear?: boolean): MemorySlice;
140
+ free([addr, numBytes]: MemorySlice): void;
167
141
  getI8(addr: number): number;
168
142
  getU8(addr: number): number;
169
143
  getI16(addr: number): number;
package/bridge.js CHANGED
@@ -198,19 +198,6 @@ let WasmBridge = class WasmBridge {
198
198
  this.exports.memory.grow(numPages);
199
199
  this.ensureMemory();
200
200
  }
201
- /**
202
- * Attempts to allocate `numBytes` using the exported WASM core API function
203
- * {@link WasmExports._wasm_allocate} (implementation specific) and returns
204
- * start address of the new memory block. If unsuccessful, throws an
205
- * {@link OutOfMemoryError}. If `clear` is true, the allocated region will
206
- * be zero-filled.
207
- *
208
- * @remarks
209
- * See {@link WasmExports._wasm_allocate} docs for further details.
210
- *
211
- * @param numBytes
212
- * @param clear
213
- */
214
201
  allocate(numBytes, clear = false) {
215
202
  const addr = this.exports._wasm_allocate(numBytes);
216
203
  if (!addr)
@@ -218,22 +205,9 @@ let WasmBridge = class WasmBridge {
218
205
  this.logger.fine(() => `allocated ${numBytes} bytes @ 0x${U32(addr)} .. 0x${U32(addr + numBytes - 1)}`);
219
206
  this.ensureMemory();
220
207
  clear && this.u8.fill(0, addr, addr + numBytes);
221
- return addr;
208
+ return [addr, numBytes];
222
209
  }
223
- /**
224
- * Frees a previous allocated memory region using the exported WASM core API
225
- * function {@link WasmExports._wasm_free} (implementation specific). The
226
- * `numBytes` value must be the same as previously given to
227
- * {@link WasmBridge.allocate}.
228
- *
229
- * @remarks
230
- * This function always succeeds, regardless of presence of an active
231
- * allocator on the WASM side or validity of given arguments.
232
- *
233
- * @param addr
234
- * @param numBytes
235
- */
236
- free(addr, numBytes) {
210
+ free([addr, numBytes]) {
237
211
  this.logger.fine(() => `freeing memory @ 0x${U32(addr)} .. 0x${U32(addr + numBytes - 1)}`);
238
212
  this.exports._wasm_free(addr, numBytes);
239
213
  }
package/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { flag, oneOf, oneOfMulti, parse, ParseError, string, strings, usage, } from "@thi.ng/args";
2
- import { isArray, isPlainObject } from "@thi.ng/checks";
2
+ import { isArray, isPlainObject, isString } from "@thi.ng/checks";
3
3
  import { illegalArgs } from "@thi.ng/errors";
4
4
  import { readJSON, readText, writeJSON, writeText } from "@thi.ng/file-io";
5
5
  import { ConsoleLogger } from "@thi.ng/logger";
@@ -84,7 +84,7 @@ const addTypeSpec = (ctx, path, coll, spec) => {
84
84
  invalidSpec(path, `${spec.name}.body must be an object`);
85
85
  for (let lang in spec.body) {
86
86
  const src = spec.body[lang];
87
- if (src[0] === "@") {
87
+ if (isString(src) && src[0] === "@") {
88
88
  spec.body[lang] = readText(src.substring(1), ctx.logger);
89
89
  }
90
90
  }
@@ -1,7 +1,8 @@
1
1
  import { BIGINT_ARRAY_CTORS, BIT_SHIFTS, TYPEDARRAY_CTORS, } from "@thi.ng/api/typedarray";
2
2
  import { isString } from "@thi.ng/checks/is-string";
3
3
  import { PKG_NAME, } from "../api.js";
4
- import { enumName, isBigNumeric, isNumeric, isPadding, isStringSlice, isWasmPrim, isWasmString, pointerFields, prefixLines, stringFields, withIndentation, } from "./utils.js";
4
+ import { ensureLines, enumName, isBigNumeric, isNumeric, isPadding, isStringSlice, isWasmPrim, isWasmString, pointerFields, prefixLines, stringFields, withIndentation, } from "./utils.js";
5
+ import { fieldType as zigFieldType } from "./zig.js";
5
6
  /**
6
7
  * TypeScript code generator. Call with options and then pass to
7
8
  * {@link generateTypes} (see its docs for further usage).
@@ -22,7 +23,7 @@ export const TYPESCRIPT = (opts = {}) => {
22
23
  const SCOPES = [/\{$/, /\}\)?[;,]?$/];
23
24
  const gen = {
24
25
  pre: (opts) => `// @ts-ignore possibly includes unused imports
25
- import { Pointer, ${__stringImpl(opts)}, WasmTypeBase, WasmTypeConstructor } from "${PKG_NAME}";${opts.pre ? `\n${opts.pre}` : ""}`,
26
+ import { MemorySlice, Pointer, ${__stringImpl(opts)}, WasmTypeBase, WasmTypeConstructor } from "${PKG_NAME}";${opts.pre ? `\n${opts.pre}` : ""}`,
26
27
  post: () => opts.post || "",
27
28
  doc: (doc, acc, opts) => {
28
29
  acc.push("/**", ...prefixLines(" * ", doc, opts.lineWidth), " */");
@@ -55,11 +56,15 @@ import { Pointer, ${__stringImpl(opts)}, WasmTypeBase, WasmTypeConstructor } fro
55
56
  for (let f of struct.fields) {
56
57
  if (isPadding(f))
57
58
  continue;
58
- f.doc && gen.doc(f.doc, lines, opts);
59
+ const doc = __docType(struct, f, opts);
60
+ doc && gen.doc(doc, lines, opts);
59
61
  const ftype = __fieldType(f, opts);
60
62
  fieldTypes[f.name] = ftype;
61
63
  lines.push(`${f.name}: ${ftype};`);
62
64
  }
65
+ if (struct.body?.ts) {
66
+ lines.push("", ...ensureLines(struct.body.ts, "decl"));
67
+ }
63
68
  lines.push("}", "");
64
69
  const pointerDecls = pointerFields(struct.fields).map((x) => {
65
70
  return `let $${x.name}: ${fieldTypes[x.name]} | null = null;`;
@@ -159,6 +164,9 @@ import { Pointer, ${__stringImpl(opts)}, WasmTypeBase, WasmTypeConstructor } fro
159
164
  // close field accessor
160
165
  lines.push(`},`);
161
166
  }
167
+ if (struct.body?.ts) {
168
+ lines.push("", ...ensureLines(struct.body.ts, "impl"), "");
169
+ }
162
170
  lines.push("};", "}", "});", "");
163
171
  acc.push(...withIndentation(lines, indent, ...SCOPES));
164
172
  },
@@ -221,3 +229,12 @@ const __mapStringArray = (target, name, type, len, isConst, isLocal = false) =>
221
229
  `for(let i = 0; i < ${len}; i++) $${name}.push(new ${type}(mem, addr + i * ${target.usizeBytes * (type === "WasmStringSlice" ? 2 : 1)}, ${isConst}));`,
222
230
  `return $${name};`,
223
231
  ];
232
+ const __docType = (parent, f, opts) => {
233
+ const doc = [...ensureLines(f.doc || [])];
234
+ if (isWasmPrim(f.type)) {
235
+ if (doc.length)
236
+ doc.push("");
237
+ doc.push(`WASM type: ${zigFieldType(parent, f, opts).type}`);
238
+ }
239
+ return doc.length ? doc : undefined;
240
+ };
@@ -1,5 +1,5 @@
1
1
  import type { BigType } from "@thi.ng/api";
2
- import type { CodeGenOpts, Field, WasmPrim, WasmPrim32 } from "../api.js";
2
+ import type { CodeGenOpts, Field, InjectedBody, WasmPrim, WasmPrim32 } from "../api.js";
3
3
  /**
4
4
  * Returns true iff `x` is a {@link WasmPrim32}.
5
5
  *
@@ -28,16 +28,6 @@ export declare const isSlice: (f: Field) => boolean;
28
28
  * @param f
29
29
  */
30
30
  export declare const isPointerLike: (f: Field) => boolean;
31
- /**
32
- * Takes an array of strings or splits given string into lines, word wraps and
33
- * then prefixes each line with given `width` and `prefix`. Returns array of new
34
- * lines.
35
- *
36
- * @param prefix
37
- * @param str
38
- * @param width
39
- */
40
- export declare const prefixLines: (prefix: string, str: string | string[], width: number) => string[];
41
31
  /**
42
32
  * Returns true if `type` is "slice".
43
33
  *
@@ -69,6 +59,17 @@ export declare const stringFields: (fields: Field[]) => Field[];
69
59
  * @internal
70
60
  */
71
61
  export declare const enumName: (opts: CodeGenOpts, name: string) => string;
62
+ /**
63
+ * Takes an array of strings or splits given string into lines, word wraps and
64
+ * then prefixes each line with given `width` and `prefix`. Returns array of new
65
+ * lines.
66
+ *
67
+ * @param prefix
68
+ * @param str
69
+ * @param width
70
+ */
71
+ export declare const prefixLines: (prefix: string, str: string | string[], width: number) => string[];
72
+ export declare const ensureLines: (src: string | string[] | InjectedBody, key?: keyof InjectedBody) => Iterable<string>;
72
73
  /**
73
74
  * Yields iterator of given lines, each with applied indentation based on given
74
75
  * scope regexp's which are applied to each line to increase or decrease
package/codegen/utils.js CHANGED
@@ -1,4 +1,6 @@
1
+ import { isArray } from "@thi.ng/checks/is-array";
1
2
  import { isString } from "@thi.ng/checks/is-string";
3
+ import { split } from "@thi.ng/strings/split";
2
4
  import { wordWrapLine, wordWrapLines } from "@thi.ng/strings/word-wrap";
3
5
  /**
4
6
  * Returns true iff `x` is a {@link WasmPrim32}.
@@ -28,18 +30,6 @@ export const isSlice = (f) => f.tag === "slice";
28
30
  * @param f
29
31
  */
30
32
  export const isPointerLike = (f) => isPointer(f) || isSlice(f) || isWasmString(f.type);
31
- /**
32
- * Takes an array of strings or splits given string into lines, word wraps and
33
- * then prefixes each line with given `width` and `prefix`. Returns array of new
34
- * lines.
35
- *
36
- * @param prefix
37
- * @param str
38
- * @param width
39
- */
40
- export const prefixLines = (prefix, str, width) => (isString(str)
41
- ? wordWrapLines(str, { width: width - prefix.length })
42
- : str.flatMap((x) => wordWrapLine(x, { width: width - prefix.length }))).map((line) => prefix + line);
43
33
  /**
44
34
  * Returns true if `type` is "slice".
45
35
  *
@@ -71,6 +61,27 @@ export const stringFields = (fields) => fields.filter((f) => isWasmString(f.type
71
61
  * @internal
72
62
  */
73
63
  export const enumName = (opts, name) => opts.uppercaseEnums ? name.toUpperCase() : name;
64
+ /**
65
+ * Takes an array of strings or splits given string into lines, word wraps and
66
+ * then prefixes each line with given `width` and `prefix`. Returns array of new
67
+ * lines.
68
+ *
69
+ * @param prefix
70
+ * @param str
71
+ * @param width
72
+ */
73
+ export const prefixLines = (prefix, str, width) => (isString(str)
74
+ ? wordWrapLines(str, { width: width - prefix.length })
75
+ : str.flatMap((x) => wordWrapLine(x, { width: width - prefix.length }))).map((line) => prefix + line);
76
+ export const ensureLines = (src, key) => isString(src)
77
+ ? split(src)
78
+ : isArray(src)
79
+ ? src
80
+ : key
81
+ ? src[key]
82
+ ? ensureLines(src[key], key)
83
+ : []
84
+ : [];
74
85
  /**
75
86
  * Yields iterator of given lines, each with applied indentation based on given
76
87
  * scope regexp's which are applied to each line to increase or decrease
package/codegen/zig.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { CodeGenOptsBase, ICodeGen } from "../api.js";
1
+ import type { CodeGenOpts, CodeGenOptsBase, Field, ICodeGen, Struct, Union } from "../api.js";
2
2
  /**
3
3
  * Zig code generator options.
4
4
  */
@@ -15,4 +15,9 @@ export interface ZigOpts extends CodeGenOptsBase {
15
15
  * @param opts
16
16
  */
17
17
  export declare const ZIG: (opts?: Partial<ZigOpts>) => ICodeGen;
18
+ /** @internal */
19
+ export declare const fieldType: (parent: Struct | Union, f: Field, opts: CodeGenOpts) => {
20
+ type: string;
21
+ defaultVal: string;
22
+ };
18
23
  //# sourceMappingURL=zig.d.ts.map
package/codegen/zig.js CHANGED
@@ -1,8 +1,7 @@
1
1
  import { isNumber } from "@thi.ng/checks/is-number";
2
2
  import { isString } from "@thi.ng/checks/is-string";
3
3
  import { unsupported } from "@thi.ng/errors/unsupported";
4
- import { split } from "@thi.ng/strings/split";
5
- import { enumName, isPadding, isStringSlice, isWasmString, prefixLines, withIndentation, } from "./utils.js";
4
+ import { ensureLines, enumName, isPadding, isStringSlice, isWasmString, prefixLines, withIndentation, } from "./utils.js";
6
5
  /**
7
6
  * Zig code generator. Call with options and then pass to {@link generateTypes}
8
7
  * (see its docs for further usage).
@@ -39,7 +38,7 @@ export const ZIG = (opts = {}) => {
39
38
  lines.push(line + ",");
40
39
  }
41
40
  if (e.body?.zig) {
42
- lines.push("", ...split(e.body.zig), "");
41
+ lines.push("", ...ensureLines(e.body.zig, "impl"), "");
43
42
  }
44
43
  lines.push("};", "");
45
44
  acc.push(...withIndentation(lines, INDENT, ...SCOPES));
@@ -75,46 +74,12 @@ const __generateFields = (gen, parent, opts) => {
75
74
  continue;
76
75
  }
77
76
  f.doc && gen.doc(f.doc, res, opts);
78
- let ftype = isWasmString(f.type)
79
- ? isStringSlice(opts.stringType)
80
- ? f.const !== false
81
- ? "[]const u8"
82
- : "[]u8"
83
- : f.const !== false
84
- ? "[*:0]const u8"
85
- : "[*:0]u8"
86
- : f.type;
87
- let defaultVal = "";
88
- switch (f.tag) {
89
- case "array":
90
- ftype =
91
- f.sentinel !== undefined
92
- ? `[${f.len}:${f.sentinel}]${ftype}`
93
- : `[${f.len}]${ftype}`;
94
- break;
95
- case "slice":
96
- ftype = `[${f.sentinel !== undefined ? ":" + f.sentinel : ""}]${f.const ? "const " : ""}${ftype}`;
97
- break;
98
- case "vec":
99
- ftype = `@Vector(${f.len}, ${ftype})`;
100
- break;
101
- case "ptr":
102
- ftype = `*${f.const ? "const " : ""}${f.len ? `[${f.len}]` : ""}${ftype}`;
103
- break;
104
- case "scalar":
105
- default:
106
- if (f.default != undefined) {
107
- if (!(isString(f.default) || isNumber(f.default))) {
108
- unsupported(`wrong default value for ${name}.${f.name} (${f.default})`);
109
- }
110
- defaultVal = ` = ${JSON.stringify(f.default)}`;
111
- }
112
- }
113
- ftypes[f.name] = ftype;
114
- res.push(`${f.name}: ${ftype}${defaultVal},`);
77
+ const { type, defaultVal } = fieldType(parent, f, opts);
78
+ ftypes[f.name] = type;
79
+ res.push(`${f.name}: ${type}${defaultVal},`);
115
80
  }
116
81
  if (parent.body?.zig) {
117
- res.push("", ...split(parent.body.zig), "");
82
+ res.push("", ...ensureLines(parent.body.zig, "impl"), "");
118
83
  }
119
84
  res.push("};");
120
85
  if (opts.debug) {
@@ -133,6 +98,45 @@ const __generateFields = (gen, parent, opts) => {
133
98
  res.push("");
134
99
  return res;
135
100
  };
101
+ /** @internal */
102
+ export const fieldType = (parent, f, opts) => {
103
+ let type = isWasmString(f.type)
104
+ ? isStringSlice(opts.stringType)
105
+ ? f.const !== false
106
+ ? "[]const u8"
107
+ : "[]u8"
108
+ : f.const !== false
109
+ ? "[*:0]const u8"
110
+ : "[*:0]u8"
111
+ : f.type;
112
+ let defaultVal = "";
113
+ switch (f.tag) {
114
+ case "array":
115
+ type =
116
+ f.sentinel !== undefined
117
+ ? `[${f.len}:${f.sentinel}]${type}`
118
+ : `[${f.len}]${type}`;
119
+ break;
120
+ case "slice":
121
+ type = `[${f.sentinel !== undefined ? ":" + f.sentinel : ""}]${f.const ? "const " : ""}${type}`;
122
+ break;
123
+ case "vec":
124
+ type = `@Vector(${f.len}, ${type})`;
125
+ break;
126
+ case "ptr":
127
+ type = `*${f.const ? "const " : ""}${f.len ? `[${f.len}]` : ""}${type}`;
128
+ break;
129
+ case "scalar":
130
+ default:
131
+ if (f.default != undefined) {
132
+ if (!(isString(f.default) || isNumber(f.default))) {
133
+ unsupported(`wrong default value for ${parent.name}.${f.name} (${f.default})`);
134
+ }
135
+ defaultVal = ` = ${JSON.stringify(f.default)}`;
136
+ }
137
+ }
138
+ return { type, defaultVal };
139
+ };
136
140
  const __packedPadding = (id, n, res) => {
137
141
  let i = 0;
138
142
  n <<= 3;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thi.ng/wasm-api",
3
- "version": "0.15.0",
3
+ "version": "0.16.0",
4
4
  "description": "Generic, modular, extensible API bridge, polyglot glue code and bindings code generators for hybrid JS & WebAssembly projects",
5
5
  "type": "module",
6
6
  "module": "./index.js",
@@ -36,27 +36,27 @@
36
36
  "test:build-zig": "zig build-lib -O ReleaseSmall -target wasm32-freestanding -dynamic --strip --pkg-begin wasmapi zig/wasmapi.zig --pkg-end test/custom.zig && wasm-dis -o custom.wast custom.wasm && cp custom.wasm test"
37
37
  },
38
38
  "dependencies": {
39
- "@thi.ng/api": "^8.4.3",
40
- "@thi.ng/args": "^2.2.6",
41
- "@thi.ng/binary": "^3.3.7",
42
- "@thi.ng/checks": "^3.3.1",
43
- "@thi.ng/compare": "^2.1.13",
44
- "@thi.ng/defmulti": "^2.1.18",
45
- "@thi.ng/errors": "^2.2.2",
46
- "@thi.ng/file-io": "^0.3.16",
47
- "@thi.ng/hex": "^2.2.1",
48
- "@thi.ng/idgen": "^2.1.15",
49
- "@thi.ng/logger": "^1.4.1",
50
- "@thi.ng/paths": "^5.1.19",
51
- "@thi.ng/strings": "^3.3.14"
39
+ "@thi.ng/api": "^8.4.4",
40
+ "@thi.ng/args": "^2.2.7",
41
+ "@thi.ng/binary": "^3.3.8",
42
+ "@thi.ng/checks": "^3.3.2",
43
+ "@thi.ng/compare": "^2.1.14",
44
+ "@thi.ng/defmulti": "^2.1.19",
45
+ "@thi.ng/errors": "^2.2.3",
46
+ "@thi.ng/file-io": "^0.3.17",
47
+ "@thi.ng/hex": "^2.2.2",
48
+ "@thi.ng/idgen": "^2.1.16",
49
+ "@thi.ng/logger": "^1.4.2",
50
+ "@thi.ng/paths": "^5.1.20",
51
+ "@thi.ng/strings": "^3.3.15"
52
52
  },
53
53
  "devDependencies": {
54
- "@microsoft/api-extractor": "^7.31.1",
55
- "@thi.ng/testament": "^0.3.3",
54
+ "@microsoft/api-extractor": "^7.33.5",
55
+ "@thi.ng/testament": "^0.3.4",
56
56
  "rimraf": "^3.0.2",
57
57
  "tools": "^0.0.1",
58
- "typedoc": "^0.22.17",
59
- "typescript": "^4.8.3"
58
+ "typedoc": "^0.23.18",
59
+ "typescript": "^4.8.4"
60
60
  },
61
61
  "keywords": [
62
62
  "allocator",
@@ -141,5 +141,5 @@
141
141
  "status": "alpha",
142
142
  "year": 2022
143
143
  },
144
- "gitHead": "cc61bc0a890288bea00b8df81ffd73bc4851ffd3\n"
144
+ "gitHead": "41e59c7ad9bf24bb0230a5f60d05715e0fc1c1e6\n"
145
145
  }