@thi.ng/wasm-api 0.13.1 → 0.15.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 +48 -1
- package/README.md +173 -108
- package/api.d.ts +83 -21
- package/api.js +10 -4
- package/bridge.js +1 -0
- package/cli.js +6 -2
- package/codegen/align.d.ts +14 -0
- package/codegen/align.js +35 -0
- package/codegen/c11.js +71 -55
- package/codegen/typescript.js +14 -11
- package/codegen/utils.d.ts +12 -4
- package/codegen/utils.js +8 -0
- package/codegen/zig.js +93 -69
- package/codegen.d.ts +2 -1
- package/codegen.js +77 -54
- package/package.json +19 -14
- package/string.d.ts +4 -0
- package/string.js +14 -3
- package/zig/managed-index.zig +223 -0
- package/{include → zig}/wasmapi.zig +43 -0
package/codegen/zig.js
CHANGED
|
@@ -2,7 +2,7 @@ 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
4
|
import { split } from "@thi.ng/strings/split";
|
|
5
|
-
import { enumName, isPadding, isStringSlice, prefixLines, withIndentation, } from "./utils.js";
|
|
5
|
+
import { enumName, isPadding, isStringSlice, isWasmString, prefixLines, withIndentation, } from "./utils.js";
|
|
6
6
|
/**
|
|
7
7
|
* Zig code generator. Call with options and then pass to {@link generateTypes}
|
|
8
8
|
* (see its docs for further usage).
|
|
@@ -45,75 +45,99 @@ export const ZIG = (opts = {}) => {
|
|
|
45
45
|
acc.push(...withIndentation(lines, INDENT, ...SCOPES));
|
|
46
46
|
},
|
|
47
47
|
struct: (struct, _, acc, opts) => {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
f.doc && gen.doc(f.doc, res, opts);
|
|
60
|
-
let ftype = f.type === "string"
|
|
61
|
-
? isStringSlice(opts.stringType)
|
|
62
|
-
? f.const !== false
|
|
63
|
-
? "[]const u8"
|
|
64
|
-
: "[]u8"
|
|
65
|
-
: f.const !== false
|
|
66
|
-
? "[*:0]const u8"
|
|
67
|
-
: "[*:0]u8"
|
|
68
|
-
: f.type;
|
|
69
|
-
let defaultVal = "";
|
|
70
|
-
switch (f.tag) {
|
|
71
|
-
case "array":
|
|
72
|
-
ftype =
|
|
73
|
-
f.sentinel !== undefined
|
|
74
|
-
? `[${f.len}:${f.sentinel}]${ftype}`
|
|
75
|
-
: `[${f.len}]${ftype}`;
|
|
76
|
-
break;
|
|
77
|
-
case "slice":
|
|
78
|
-
ftype = `[${f.sentinel !== undefined ? ":" + f.sentinel : ""}]${f.const ? "const " : ""}${ftype}`;
|
|
79
|
-
break;
|
|
80
|
-
case "vec":
|
|
81
|
-
ftype = `@Vector(${f.len}, ${ftype})`;
|
|
82
|
-
break;
|
|
83
|
-
case "ptr":
|
|
84
|
-
ftype = `*${f.const ? "const " : ""}${f.len ? `[${f.len}]` : ""}${ftype}`;
|
|
85
|
-
break;
|
|
86
|
-
case "scalar":
|
|
87
|
-
default:
|
|
88
|
-
if (f.default != undefined) {
|
|
89
|
-
if (!(isString(f.default) || isNumber(f.default))) {
|
|
90
|
-
unsupported(`wrong default value for ${name}.${f.name} (${f.default})`);
|
|
91
|
-
}
|
|
92
|
-
defaultVal = ` = ${JSON.stringify(f.default)}`;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
ftypes[f.name] = ftype;
|
|
96
|
-
res.push(`${f.name}: ${ftype}${defaultVal},`);
|
|
97
|
-
}
|
|
98
|
-
if (struct.body?.zig) {
|
|
99
|
-
res.push("", ...split(struct.body.zig), "");
|
|
100
|
-
}
|
|
101
|
-
res.push("};");
|
|
102
|
-
if (opts.debug) {
|
|
103
|
-
const fn = (fname, body) => res.push("", `export fn ${name}_${fname}() usize {`, `return ${body};`, `}`);
|
|
104
|
-
fn("align", `@alignOf(${name})`);
|
|
105
|
-
fn("size", `@sizeOf(${name})`);
|
|
106
|
-
for (let f of struct.fields) {
|
|
107
|
-
if (isPadding(f))
|
|
108
|
-
continue;
|
|
109
|
-
fn(f.name + "_align", `@alignOf(${ftypes[f.name]})`);
|
|
110
|
-
fn(f.name + "_offset", `@offsetOf(${name}, "${f.name}")`);
|
|
111
|
-
fn(f.name + "_size", `@sizeOf(${ftypes[f.name]})`);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
res.push("");
|
|
115
|
-
acc.push(...withIndentation(res, INDENT, ...SCOPES));
|
|
48
|
+
acc.push(...withIndentation([
|
|
49
|
+
`pub const ${struct.name} = ${struct.tag ? struct.tag + " " : ""}struct {`,
|
|
50
|
+
...__generateFields(gen, struct, opts),
|
|
51
|
+
], INDENT, ...SCOPES));
|
|
52
|
+
},
|
|
53
|
+
union: (union, _, acc, opts) => {
|
|
54
|
+
acc.push(...withIndentation([
|
|
55
|
+
`pub const ${union.name} = ${union.tag ? union.tag + " " : ""}union {`,
|
|
56
|
+
...__generateFields(gen, union, opts),
|
|
57
|
+
], INDENT, ...SCOPES));
|
|
116
58
|
},
|
|
117
59
|
};
|
|
118
60
|
return gen;
|
|
119
61
|
};
|
|
62
|
+
const __generateFields = (gen, parent, opts) => {
|
|
63
|
+
const res = [];
|
|
64
|
+
const ftypes = {};
|
|
65
|
+
const isUnion = parent.type === "union";
|
|
66
|
+
const name = parent.name;
|
|
67
|
+
let padID = 0;
|
|
68
|
+
for (let f of parent.fields) {
|
|
69
|
+
// autolabel explicit padding fields
|
|
70
|
+
if (isPadding(f)) {
|
|
71
|
+
parent.tag === "packed"
|
|
72
|
+
? __packedPadding(padID, f.pad, res)
|
|
73
|
+
: res.push(`__pad${padID}: [${f.pad}]u8,`);
|
|
74
|
+
padID++;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
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},`);
|
|
115
|
+
}
|
|
116
|
+
if (parent.body?.zig) {
|
|
117
|
+
res.push("", ...split(parent.body.zig), "");
|
|
118
|
+
}
|
|
119
|
+
res.push("};");
|
|
120
|
+
if (opts.debug) {
|
|
121
|
+
const fn = (fname, body) => res.push("", `export fn ${name}_${fname}() usize {`, `return ${body};`, `}`);
|
|
122
|
+
fn("align", `@alignOf(${name})`);
|
|
123
|
+
fn("size", `@sizeOf(${name})`);
|
|
124
|
+
for (let f of parent.fields) {
|
|
125
|
+
if (isPadding(f))
|
|
126
|
+
continue;
|
|
127
|
+
fn(f.name + "_align", `@alignOf(${ftypes[f.name]})`);
|
|
128
|
+
!isUnion &&
|
|
129
|
+
fn(f.name + "_offset", `@offsetOf(${name}, "${f.name}")`);
|
|
130
|
+
fn(f.name + "_size", `@sizeOf(${ftypes[f.name]})`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
res.push("");
|
|
134
|
+
return res;
|
|
135
|
+
};
|
|
136
|
+
const __packedPadding = (id, n, res) => {
|
|
137
|
+
let i = 0;
|
|
138
|
+
n <<= 3;
|
|
139
|
+
for (; n >= 128; n -= 128, i++) {
|
|
140
|
+
res.push(`__pad${id}_${i}: u128,`);
|
|
141
|
+
}
|
|
142
|
+
res.push(`__pad${id}_${i}: u${n},`);
|
|
143
|
+
};
|
package/codegen.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CodeGenOpts, ICodeGen, TypeColl } from "./api.js";
|
|
2
|
+
export declare const DEFAULT_CODEGEN_OPTS: CodeGenOpts;
|
|
2
3
|
/**
|
|
3
4
|
* Takes a type collection and analyzes each analyzed to compute individual
|
|
4
5
|
* alignments and sizes.
|
|
@@ -11,7 +12,7 @@ import { CodeGenOpts, ICodeGen, TypeColl } from "./api.js";
|
|
|
11
12
|
*
|
|
12
13
|
* @internal
|
|
13
14
|
*/
|
|
14
|
-
export declare const prepareTypes: (types: TypeColl, opts: CodeGenOpts) =>
|
|
15
|
+
export declare const prepareTypes: (types: TypeColl, opts: CodeGenOpts) => TypeColl;
|
|
15
16
|
/**
|
|
16
17
|
* Code generator main entry point. Takes an object of {@link TopLevelType}
|
|
17
18
|
* definitions, an actual code generator implementation for a single target
|
package/codegen.js
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
import { SIZEOF } from "@thi.ng/api/typedarray";
|
|
2
|
-
import { align } from "@thi.ng/binary/align";
|
|
3
|
-
import { ceilPow2 } from "@thi.ng/binary/pow";
|
|
4
2
|
import { compareByKey } from "@thi.ng/compare/keys";
|
|
5
3
|
import { compareNumDesc } from "@thi.ng/compare/numeric";
|
|
6
4
|
import { DEFAULT, defmulti } from "@thi.ng/defmulti/defmulti";
|
|
7
5
|
import { illegalArgs } from "@thi.ng/errors/illegal-arguments";
|
|
8
|
-
import { PKG_NAME,
|
|
9
|
-
import {
|
|
6
|
+
import { PKG_NAME, WASM32, } from "./api.js";
|
|
7
|
+
import { selectAlignment } from "./codegen/align.js";
|
|
8
|
+
import { isBigNumeric, isNumeric, isPointer, isPointerLike, isSlice, isStringSlice, isWasmString, } from "./codegen/utils.js";
|
|
9
|
+
export const DEFAULT_CODEGEN_OPTS = {
|
|
10
|
+
debug: false,
|
|
11
|
+
header: true,
|
|
12
|
+
lineWidth: 80,
|
|
13
|
+
stringType: "slice",
|
|
14
|
+
target: WASM32,
|
|
15
|
+
uppercaseEnums: true,
|
|
16
|
+
};
|
|
10
17
|
const sizeOf = defmulti((x) => x.type, {}, {
|
|
11
|
-
[DEFAULT]: (field, types, opts) => {
|
|
18
|
+
[DEFAULT]: (field, types, align, opts) => {
|
|
12
19
|
if (field.__size)
|
|
13
20
|
return field.__size;
|
|
14
21
|
if (field.pad != null) {
|
|
@@ -16,18 +23,20 @@ const sizeOf = defmulti((x) => x.type, {}, {
|
|
|
16
23
|
return (field.__size = field.pad);
|
|
17
24
|
}
|
|
18
25
|
let size = 0;
|
|
19
|
-
if (field
|
|
20
|
-
size =
|
|
26
|
+
if (isPointer(field)) {
|
|
27
|
+
size = opts.target.usizeBytes;
|
|
21
28
|
}
|
|
22
|
-
else if (field
|
|
23
|
-
size =
|
|
29
|
+
else if (isSlice(field)) {
|
|
30
|
+
size = opts.target.usizeBytes * 2;
|
|
24
31
|
}
|
|
25
32
|
else {
|
|
26
|
-
size =
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
33
|
+
size =
|
|
34
|
+
isNumeric(field.type) || isBigNumeric(field.type)
|
|
35
|
+
? SIZEOF[field.type]
|
|
36
|
+
: isWasmString(field.type)
|
|
37
|
+
? opts.target.usizeBytes *
|
|
38
|
+
(isStringSlice(opts.stringType) ? 2 : 1)
|
|
39
|
+
: sizeOf(types[field.type], types, align, opts);
|
|
31
40
|
if (field.tag == "array" || field.tag === "vec") {
|
|
32
41
|
size *= field.len;
|
|
33
42
|
if (field.sentinel !== undefined && field.tag === "array") {
|
|
@@ -35,79 +44,95 @@ const sizeOf = defmulti((x) => x.type, {}, {
|
|
|
35
44
|
}
|
|
36
45
|
}
|
|
37
46
|
}
|
|
38
|
-
return (field.__size = align(size, field.__align));
|
|
47
|
+
return (field.__size = align.size(size, field.__align));
|
|
39
48
|
},
|
|
40
49
|
enum: (type) => {
|
|
41
50
|
if (type.__size)
|
|
42
51
|
return type.__size;
|
|
43
52
|
return (type.__size = SIZEOF[type.tag]);
|
|
44
53
|
},
|
|
45
|
-
struct: (type, types, opts) => {
|
|
54
|
+
struct: (type, types, align, opts) => {
|
|
46
55
|
if (type.__size)
|
|
47
56
|
return type.__size;
|
|
48
|
-
|
|
49
|
-
let
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
f
|
|
53
|
-
|
|
57
|
+
let offset = 0;
|
|
58
|
+
for (let f of type.fields) {
|
|
59
|
+
offset = align.offset(offset, f.__align);
|
|
60
|
+
f.__offset = offset;
|
|
61
|
+
offset += sizeOf(f, types, align, opts);
|
|
62
|
+
}
|
|
63
|
+
return (type.__size = align.size(offset, type.__align));
|
|
64
|
+
},
|
|
65
|
+
union: (type, types, align, opts) => {
|
|
66
|
+
if (type.__size)
|
|
67
|
+
return type.__size;
|
|
68
|
+
let maxSize = 0;
|
|
69
|
+
for (let f of type.fields) {
|
|
70
|
+
f.__offset = 0;
|
|
71
|
+
maxSize = Math.max(maxSize, sizeOf(f, types, align, opts));
|
|
54
72
|
}
|
|
55
|
-
return (type.__size = align(
|
|
73
|
+
return (type.__size = align.size(maxSize, type.__align));
|
|
56
74
|
},
|
|
57
75
|
});
|
|
58
76
|
const alignOf = defmulti((x) => x.type, {}, {
|
|
59
|
-
[DEFAULT]: (field, types) => {
|
|
77
|
+
[DEFAULT]: (field, types, align, opts) => {
|
|
60
78
|
if (field.__align)
|
|
61
79
|
return field.__align;
|
|
80
|
+
if (field.type === "usize") {
|
|
81
|
+
field.type = opts.target.usize;
|
|
82
|
+
}
|
|
62
83
|
if (field.pad)
|
|
63
84
|
return (field.__align = 1);
|
|
64
|
-
|
|
65
|
-
?
|
|
66
|
-
:
|
|
67
|
-
?
|
|
68
|
-
: alignOf(types[field.type], types);
|
|
69
|
-
if (field.tag === "vec") {
|
|
70
|
-
align *= ceilPow2(field.len);
|
|
71
|
-
}
|
|
72
|
-
field.__align = align;
|
|
73
|
-
return align;
|
|
85
|
+
return (field.__align = isPointerLike(field)
|
|
86
|
+
? align.align({ type: opts.target.usize })
|
|
87
|
+
: isNumeric(field.type) || isBigNumeric(field.type)
|
|
88
|
+
? align.align(field)
|
|
89
|
+
: alignOf(types[field.type], types, selectAlignment(types[field.type]), opts));
|
|
74
90
|
},
|
|
75
|
-
enum: (type) => {
|
|
91
|
+
enum: (type, _, align) => {
|
|
76
92
|
const e = type;
|
|
77
93
|
if (!e.tag)
|
|
78
94
|
e.tag = "i32";
|
|
79
|
-
return (e.__align =
|
|
95
|
+
return (e.__align = align.align({
|
|
96
|
+
type: e.tag,
|
|
97
|
+
}));
|
|
80
98
|
},
|
|
81
|
-
struct: (type, types) => {
|
|
82
|
-
|
|
83
|
-
let
|
|
84
|
-
|
|
85
|
-
|
|
99
|
+
struct: (type, types, align, opts) => {
|
|
100
|
+
let maxAlign = 1;
|
|
101
|
+
for (let f of type.fields) {
|
|
102
|
+
maxAlign = Math.max(maxAlign, alignOf(f, types, align, opts));
|
|
103
|
+
}
|
|
104
|
+
return (type.__align = maxAlign);
|
|
105
|
+
},
|
|
106
|
+
union: (type, types, align, opts) => {
|
|
107
|
+
let maxAlign = 1;
|
|
108
|
+
for (let f of type.fields) {
|
|
109
|
+
maxAlign = Math.max(maxAlign, alignOf(f, types, align, opts));
|
|
86
110
|
}
|
|
87
111
|
return (type.__align = maxAlign);
|
|
88
112
|
},
|
|
89
113
|
});
|
|
90
114
|
const prepareType = defmulti((x) => x.type, {}, {
|
|
91
|
-
[DEFAULT]: (x, types, opts) => {
|
|
115
|
+
[DEFAULT]: (x, types, alignImpl, opts) => {
|
|
92
116
|
if (x.__align && x.__size)
|
|
93
117
|
return;
|
|
94
|
-
alignOf(x, types);
|
|
95
|
-
sizeOf(x, types, opts);
|
|
118
|
+
alignOf(x, types, alignImpl, opts);
|
|
119
|
+
sizeOf(x, types, alignImpl, opts);
|
|
96
120
|
},
|
|
97
|
-
struct: (x, types, opts) => {
|
|
121
|
+
struct: (x, types, align, opts) => {
|
|
98
122
|
if (x.__align && x.__size)
|
|
99
123
|
return;
|
|
100
124
|
const struct = x;
|
|
101
|
-
alignOf(struct, types);
|
|
125
|
+
alignOf(struct, types, align, opts);
|
|
102
126
|
if (struct.auto) {
|
|
103
127
|
struct.fields.sort(compareByKey("__align", compareNumDesc));
|
|
104
128
|
}
|
|
105
129
|
for (let f of struct.fields) {
|
|
106
|
-
|
|
107
|
-
|
|
130
|
+
const type = types[f.type];
|
|
131
|
+
if (type) {
|
|
132
|
+
prepareType(type, types, selectAlignment(type), opts);
|
|
108
133
|
}
|
|
109
134
|
}
|
|
110
|
-
sizeOf(struct, types, opts);
|
|
135
|
+
sizeOf(struct, types, align, opts);
|
|
111
136
|
},
|
|
112
137
|
});
|
|
113
138
|
/**
|
|
@@ -124,8 +149,9 @@ const prepareType = defmulti((x) => x.type, {}, {
|
|
|
124
149
|
*/
|
|
125
150
|
export const prepareTypes = (types, opts) => {
|
|
126
151
|
for (let id in types) {
|
|
127
|
-
prepareType(types[id], types, opts);
|
|
152
|
+
prepareType(types[id], types, selectAlignment(types[id]), opts);
|
|
128
153
|
}
|
|
154
|
+
return types;
|
|
129
155
|
};
|
|
130
156
|
/**
|
|
131
157
|
* Code generator main entry point. Takes an object of {@link TopLevelType}
|
|
@@ -144,10 +170,7 @@ export const prepareTypes = (types, opts) => {
|
|
|
144
170
|
*/
|
|
145
171
|
export const generateTypes = (types, codegen, opts = {}) => {
|
|
146
172
|
const $opts = {
|
|
147
|
-
|
|
148
|
-
stringType: "slice",
|
|
149
|
-
uppercaseEnums: true,
|
|
150
|
-
lineWidth: 80,
|
|
173
|
+
...DEFAULT_CODEGEN_OPTS,
|
|
151
174
|
...opts,
|
|
152
175
|
};
|
|
153
176
|
prepareTypes(types, $opts);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thi.ng/wasm-api",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.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",
|
|
@@ -33,26 +33,26 @@
|
|
|
33
33
|
"doc:stats": "tools:module-stats",
|
|
34
34
|
"pub": "yarn npm publish --access public",
|
|
35
35
|
"test": "testament test",
|
|
36
|
-
"test:build-zig": "zig build-lib -O ReleaseSmall -target wasm32-freestanding -dynamic --strip --pkg-begin wasmapi
|
|
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
39
|
"@thi.ng/api": "^8.4.3",
|
|
40
|
-
"@thi.ng/args": "^2.2.
|
|
41
|
-
"@thi.ng/binary": "^3.3.
|
|
42
|
-
"@thi.ng/checks": "^3.
|
|
40
|
+
"@thi.ng/args": "^2.2.6",
|
|
41
|
+
"@thi.ng/binary": "^3.3.7",
|
|
42
|
+
"@thi.ng/checks": "^3.3.1",
|
|
43
43
|
"@thi.ng/compare": "^2.1.13",
|
|
44
|
-
"@thi.ng/defmulti": "^2.1.
|
|
44
|
+
"@thi.ng/defmulti": "^2.1.18",
|
|
45
45
|
"@thi.ng/errors": "^2.2.2",
|
|
46
|
-
"@thi.ng/file-io": "^0.3.
|
|
46
|
+
"@thi.ng/file-io": "^0.3.16",
|
|
47
47
|
"@thi.ng/hex": "^2.2.1",
|
|
48
48
|
"@thi.ng/idgen": "^2.1.15",
|
|
49
|
-
"@thi.ng/logger": "^1.4.
|
|
50
|
-
"@thi.ng/paths": "^5.1.
|
|
49
|
+
"@thi.ng/logger": "^1.4.1",
|
|
50
|
+
"@thi.ng/paths": "^5.1.19",
|
|
51
51
|
"@thi.ng/strings": "^3.3.14"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@microsoft/api-extractor": "^7.31.1",
|
|
55
|
-
"@thi.ng/testament": "^0.3.
|
|
55
|
+
"@thi.ng/testament": "^0.3.3",
|
|
56
56
|
"rimraf": "^3.0.2",
|
|
57
57
|
"tools": "^0.0.1",
|
|
58
58
|
"typedoc": "^0.22.17",
|
|
@@ -62,13 +62,15 @@
|
|
|
62
62
|
"allocator",
|
|
63
63
|
"api",
|
|
64
64
|
"bindings",
|
|
65
|
+
"browser",
|
|
65
66
|
"c",
|
|
66
67
|
"codegen",
|
|
67
68
|
"enum",
|
|
68
69
|
"event",
|
|
69
|
-
"
|
|
70
|
+
"interop",
|
|
70
71
|
"logger",
|
|
71
72
|
"memory",
|
|
73
|
+
"modular",
|
|
72
74
|
"polyglot",
|
|
73
75
|
"string",
|
|
74
76
|
"struct",
|
|
@@ -77,7 +79,6 @@
|
|
|
77
79
|
"utf8",
|
|
78
80
|
"wasm",
|
|
79
81
|
"webassembly",
|
|
80
|
-
"wrapper",
|
|
81
82
|
"ziglang"
|
|
82
83
|
],
|
|
83
84
|
"publishConfig": {
|
|
@@ -94,8 +95,9 @@
|
|
|
94
95
|
"*.js",
|
|
95
96
|
"*.d.ts",
|
|
96
97
|
"bin",
|
|
98
|
+
"codegen",
|
|
97
99
|
"include",
|
|
98
|
-
"
|
|
100
|
+
"zig"
|
|
99
101
|
],
|
|
100
102
|
"exports": {
|
|
101
103
|
".": {
|
|
@@ -107,6 +109,9 @@
|
|
|
107
109
|
"./bridge": {
|
|
108
110
|
"default": "./bridge.js"
|
|
109
111
|
},
|
|
112
|
+
"./codegen/align": {
|
|
113
|
+
"default": "./codegen/align.js"
|
|
114
|
+
},
|
|
110
115
|
"./codegen/c11": {
|
|
111
116
|
"default": "./codegen/c11.js"
|
|
112
117
|
},
|
|
@@ -136,5 +141,5 @@
|
|
|
136
141
|
"status": "alpha",
|
|
137
142
|
"year": 2022
|
|
138
143
|
},
|
|
139
|
-
"gitHead": "
|
|
144
|
+
"gitHead": "cc61bc0a890288bea00b8df81ffd73bc4851ffd3\n"
|
|
140
145
|
}
|
package/string.d.ts
CHANGED
|
@@ -3,6 +3,10 @@ import type { IWasmMemoryAccess, ReadonlyWasmString } from "./api.js";
|
|
|
3
3
|
* Memory mapped string wrapper for Zig-style UTF-8 encoded byte slices (aka
|
|
4
4
|
* pointer & length pair). The actual JS string can be obtained via
|
|
5
5
|
* {@link WasmStringSlice.deref} and mutated via {@link WasmStringSlice.set}.
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* Currently only supports wasm32 target, need alt. solution for 64bit (possibly
|
|
9
|
+
* diff implementation) using bigint addresses (TODO)
|
|
6
10
|
*/
|
|
7
11
|
export declare class WasmStringSlice implements ReadonlyWasmString {
|
|
8
12
|
readonly mem: IWasmMemoryAccess;
|
package/string.js
CHANGED
|
@@ -3,6 +3,10 @@ import { unsupported } from "@thi.ng/errors/unsupported";
|
|
|
3
3
|
* Memory mapped string wrapper for Zig-style UTF-8 encoded byte slices (aka
|
|
4
4
|
* pointer & length pair). The actual JS string can be obtained via
|
|
5
5
|
* {@link WasmStringSlice.deref} and mutated via {@link WasmStringSlice.set}.
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* Currently only supports wasm32 target, need alt. solution for 64bit (possibly
|
|
9
|
+
* diff implementation) using bigint addresses (TODO)
|
|
6
10
|
*/
|
|
7
11
|
export class WasmStringSlice {
|
|
8
12
|
constructor(mem, base, isConst = true) {
|
|
@@ -15,12 +19,14 @@ export class WasmStringSlice {
|
|
|
15
19
|
* Returns string start address (deref'd pointer).
|
|
16
20
|
*/
|
|
17
21
|
get addr() {
|
|
22
|
+
this.mem.ensureMemory();
|
|
18
23
|
return this.mem.u32[this.base >>> 2];
|
|
19
24
|
}
|
|
20
25
|
/**
|
|
21
26
|
* Returns string length (read from memory)
|
|
22
27
|
*/
|
|
23
28
|
get length() {
|
|
29
|
+
this.mem.ensureMemory();
|
|
24
30
|
return this.mem.u32[(this.base + 4) >>> 2];
|
|
25
31
|
}
|
|
26
32
|
/**
|
|
@@ -48,6 +54,7 @@ export class WasmStringSlice {
|
|
|
48
54
|
* @param str
|
|
49
55
|
*/
|
|
50
56
|
set(str) {
|
|
57
|
+
this.mem.ensureMemory();
|
|
51
58
|
if (typeof str === "string") {
|
|
52
59
|
if (this.isConst)
|
|
53
60
|
unsupported("can't mutate const string");
|
|
@@ -65,6 +72,7 @@ export class WasmStringSlice {
|
|
|
65
72
|
* @param len
|
|
66
73
|
*/
|
|
67
74
|
setSlice(addr, len) {
|
|
75
|
+
this.mem.ensureMemory();
|
|
68
76
|
this.mem.u32[this.base >>> 2] = addr;
|
|
69
77
|
this.mem.u32[(this.base + 4) >>> 2] = len;
|
|
70
78
|
}
|
|
@@ -93,18 +101,20 @@ export class WasmStringPtr {
|
|
|
93
101
|
* Returns string start address (deref'd pointer).
|
|
94
102
|
*/
|
|
95
103
|
get addr() {
|
|
104
|
+
this.mem.ensureMemory();
|
|
96
105
|
return this.mem.u32[this.base >>> 2];
|
|
97
106
|
}
|
|
98
107
|
set addr(addr) {
|
|
108
|
+
this.mem.ensureMemory();
|
|
99
109
|
this.mem.u32[this.base >>> 2] = addr;
|
|
100
110
|
}
|
|
101
111
|
/**
|
|
102
112
|
* Returns computed string length (scanning memory for zero sentinel)
|
|
103
113
|
*/
|
|
104
114
|
get length() {
|
|
105
|
-
|
|
106
|
-
const idx = this.mem.u8.indexOf(0, addr);
|
|
107
|
-
return idx >= 0 ? idx - addr : 0;
|
|
115
|
+
this.mem.ensureMemory();
|
|
116
|
+
const idx = this.mem.u8.indexOf(0, this.addr);
|
|
117
|
+
return idx >= 0 ? idx - this.addr : 0;
|
|
108
118
|
}
|
|
109
119
|
/**
|
|
110
120
|
* Returns memory as JS string (aka wrapper for
|
|
@@ -137,6 +147,7 @@ export class WasmStringPtr {
|
|
|
137
147
|
if (typeof str === "string") {
|
|
138
148
|
if (this.isConst)
|
|
139
149
|
unsupported("can't mutate const string");
|
|
150
|
+
this.mem.ensureMemory();
|
|
140
151
|
this.mem.setString(str, addr, this.mem.u8.byteLength - addr, true);
|
|
141
152
|
}
|
|
142
153
|
else {
|