@thi.ng/wasm-api 0.1.0 → 0.3.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 +29 -1
- package/README.md +147 -26
- package/api.d.ts +46 -13
- package/bridge.d.ts +98 -51
- package/bridge.js +242 -74
- package/dev/custom.zig +12 -0
- package/dev/fieldinfo.zig +135 -0
- package/dev/hello.zig +2 -1
- package/dev/zig-cache/o/85202d15b9c43c8c66de01ab98d6eb2c/builtin.zig +39 -0
- package/dev/zig-cache/o/9e1187e9310422c9c2330ebceeaecce7/builtin.zig +39 -0
- package/object-index.d.ts +66 -11
- package/object-index.js +60 -17
- package/package.json +8 -5
- package/test/custom.zig +12 -0
- package/test/zig-cache/o/117d44467ded6ce3864cde3c180ef73c/builtin.zig +39 -0
- package/zig/core.zig +58 -22
- package/doc/assets/main.js +0 -52
- package/doc/assets/search.js +0 -1
package/bridge.js
CHANGED
|
@@ -1,14 +1,31 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { U16, U32, U8 } from "@thi.ng/hex";
|
|
1
|
+
import { illegalArgs } from "@thi.ng/errors/illegal-arguments";
|
|
2
|
+
import { U16, U32, U64HL, U8 } from "@thi.ng/hex";
|
|
3
3
|
import { ConsoleLogger } from "@thi.ng/logger/console";
|
|
4
|
+
const B32 = BigInt(32);
|
|
5
|
+
/**
|
|
6
|
+
* The main interop API bridge between the JS host environment and a WebAssembly
|
|
7
|
+
* module. This class provides a small core API with various typed accessors and
|
|
8
|
+
* utils to exchange data (scalars, arrays, strings etc.) via the WASM module's
|
|
9
|
+
* memory.
|
|
10
|
+
*
|
|
11
|
+
* @remarks
|
|
12
|
+
* All typed memory accessors are assuming the given lookup addresses are
|
|
13
|
+
* properly aligned to the corresponding primitive types (e.g. f32 values are
|
|
14
|
+
* aligned to 4 byte boundaries, f64 to 8 bytes etc.) Unaligned access is
|
|
15
|
+
* explicitly **not supported**! If you need such, please refer to other
|
|
16
|
+
* mechanisms like JS `DataView`...
|
|
17
|
+
*
|
|
18
|
+
* 64bit integers are handled via JS `BigInt` and hence require the host env to
|
|
19
|
+
* support it. No polyfill is provided.
|
|
20
|
+
*/
|
|
4
21
|
export class WasmBridge {
|
|
5
|
-
constructor(logger = new ConsoleLogger("wasm")
|
|
22
|
+
constructor(modules = {}, logger = new ConsoleLogger("wasm")) {
|
|
23
|
+
this.modules = modules;
|
|
6
24
|
this.logger = logger;
|
|
7
|
-
this.children = children;
|
|
8
25
|
this.utf8Decoder = new TextDecoder();
|
|
9
26
|
this.utf8Encoder = new TextEncoder();
|
|
10
27
|
const logN = (x) => this.logger.debug(x);
|
|
11
|
-
const logA = (method) => (
|
|
28
|
+
const logA = (method) => (addr, len) => this.logger.debug(method(addr, len).join(", "));
|
|
12
29
|
this.core = {
|
|
13
30
|
printI8: logN,
|
|
14
31
|
printU8: logN,
|
|
@@ -17,8 +34,11 @@ export class WasmBridge {
|
|
|
17
34
|
printU16: logN,
|
|
18
35
|
printU16Hex: (x) => this.logger.debug(`0x${U16(x)}`),
|
|
19
36
|
printI32: logN,
|
|
20
|
-
printU32:
|
|
37
|
+
printU32: (x) => this.logger.debug(x >>> 0),
|
|
21
38
|
printU32Hex: (x) => this.logger.debug(`0x${U32(x)}`),
|
|
39
|
+
_printI64: (hi, lo) => this.logger.debug((BigInt(hi) << B32) | BigInt(lo)),
|
|
40
|
+
_printU64: (hi, lo) => this.logger.debug((BigInt(hi >>> 0) << B32) | BigInt(lo >>> 0)),
|
|
41
|
+
_printU64Hex: (hi, lo) => this.logger.debug(`0x${U64HL(hi, lo)}`),
|
|
22
42
|
printF32: logN,
|
|
23
43
|
printF64: logN,
|
|
24
44
|
_printI8Array: logA(this.getI8Array.bind(this)),
|
|
@@ -27,110 +47,258 @@ export class WasmBridge {
|
|
|
27
47
|
_printU16Array: logA(this.getU16Array.bind(this)),
|
|
28
48
|
_printI32Array: logA(this.getI32Array.bind(this)),
|
|
29
49
|
_printU32Array: logA(this.getU32Array.bind(this)),
|
|
50
|
+
_printI64Array: logA(this.getI64Array.bind(this)),
|
|
51
|
+
_printU64Array: logA(this.getU64Array.bind(this)),
|
|
30
52
|
_printF32Array: logA(this.getF32Array.bind(this)),
|
|
31
53
|
_printF64Array: logA(this.getF64Array.bind(this)),
|
|
32
|
-
_printStr0: (
|
|
33
|
-
_printStr: (
|
|
54
|
+
_printStr0: (addr) => this.logger.debug(this.getString(addr, 0)),
|
|
55
|
+
_printStr: (addr, len) => this.logger.debug(this.getString(addr, len)),
|
|
34
56
|
};
|
|
35
57
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
58
|
+
/**
|
|
59
|
+
* Instantiates WASM module from given `src` (and optional provided extra
|
|
60
|
+
* imports), then automatically calls {@link WasmBridge.init} with the
|
|
61
|
+
* modules exports.
|
|
62
|
+
*
|
|
63
|
+
* @remarks
|
|
64
|
+
* If the given `src` is a `Response` or `Promise<Response>`, the module
|
|
65
|
+
* will be instantiated via `WebAssembly.instantiateStreaming()`, otherwise
|
|
66
|
+
* the non-streaming version will be used.
|
|
67
|
+
*
|
|
68
|
+
* @param src
|
|
69
|
+
* @param imports
|
|
70
|
+
*/
|
|
71
|
+
async instantiate(src, imports) {
|
|
72
|
+
const $src = await src;
|
|
73
|
+
const $imports = { ...imports, ...this.getImports() };
|
|
74
|
+
let wasm;
|
|
75
|
+
if ($src instanceof Response) {
|
|
76
|
+
wasm = await WebAssembly.instantiateStreaming($src, $imports);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
wasm = await WebAssembly.instantiate($src, $imports);
|
|
80
|
+
}
|
|
81
|
+
return this.init(wasm.instance.exports);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Receives the WASM module's exports, stores the for future reference and
|
|
85
|
+
* then initializes all declared bridge child API modules. Returns false if
|
|
86
|
+
* any of the module initializations failed.
|
|
87
|
+
*
|
|
88
|
+
* @param exports
|
|
89
|
+
*/
|
|
90
|
+
async init(exports) {
|
|
91
|
+
this.exports = exports;
|
|
92
|
+
const buf = exports.memory.buffer;
|
|
93
|
+
this.i8 = new Int8Array(buf);
|
|
94
|
+
this.u8 = new Uint8Array(buf);
|
|
95
|
+
this.i16 = new Int16Array(buf);
|
|
96
|
+
this.u16 = new Uint16Array(buf);
|
|
97
|
+
this.i32 = new Int32Array(buf);
|
|
98
|
+
this.u32 = new Uint32Array(buf);
|
|
99
|
+
this.i64 = new BigInt64Array(buf);
|
|
100
|
+
this.u64 = new BigUint64Array(buf);
|
|
101
|
+
this.f32 = new Float32Array(buf);
|
|
102
|
+
this.f64 = new Float64Array(buf);
|
|
103
|
+
for (let id in this.modules) {
|
|
104
|
+
this.logger.debug(`initializing API module: ${id}`);
|
|
105
|
+
const status = await this.modules[id].init(this);
|
|
47
106
|
if (!status)
|
|
48
107
|
return false;
|
|
49
108
|
}
|
|
50
109
|
return true;
|
|
51
110
|
}
|
|
52
111
|
/**
|
|
53
|
-
*
|
|
54
|
-
*
|
|
112
|
+
* Required use for WASM module instantiation to provide JS imports to the
|
|
113
|
+
* module. Returns an object of all WASM imports declared by the bridge core
|
|
114
|
+
* API and any provided bridge API modules.
|
|
115
|
+
*
|
|
116
|
+
* @remarks
|
|
117
|
+
* Since all declared imports will be merged into a single flat namespace,
|
|
118
|
+
* it's recommended to use per-module naming prefixes to avoid clashes. If
|
|
119
|
+
* there're any naming clashes, this function will throw an error.
|
|
55
120
|
*/
|
|
56
121
|
getImports() {
|
|
57
122
|
const env = { ...this.core };
|
|
58
|
-
for (let
|
|
59
|
-
|
|
123
|
+
for (let id in this.modules) {
|
|
124
|
+
const imports = this.modules[id].getImports();
|
|
125
|
+
// check for naming clashes
|
|
126
|
+
for (let k in imports) {
|
|
127
|
+
if (env[k] !== undefined) {
|
|
128
|
+
illegalArgs(`attempt to redeclare import: ${k} by API module ${id}`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
Object.assign(env, imports);
|
|
132
|
+
}
|
|
60
133
|
return { env };
|
|
61
134
|
}
|
|
62
|
-
|
|
63
|
-
return this.i8
|
|
135
|
+
getI8(addr) {
|
|
136
|
+
return this.i8[addr];
|
|
64
137
|
}
|
|
65
|
-
|
|
66
|
-
return this.u8
|
|
138
|
+
getU8(addr) {
|
|
139
|
+
return this.u8[addr];
|
|
67
140
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
return this.i16.subarray(ptr, ptr + len);
|
|
141
|
+
getI16(addr) {
|
|
142
|
+
return this.i16[addr >> 1];
|
|
71
143
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
return this.u16.subarray(ptr, ptr + len);
|
|
144
|
+
getU16(addr) {
|
|
145
|
+
return this.u16[addr >> 1];
|
|
75
146
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
return this.i32.subarray(ptr, ptr + len);
|
|
147
|
+
getI32(addr) {
|
|
148
|
+
return this.i32[addr >> 2];
|
|
79
149
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
return this.u32.subarray(ptr, ptr + len);
|
|
150
|
+
getU32(addr) {
|
|
151
|
+
return this.u32[addr >> 2];
|
|
83
152
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
return this.f32.subarray(ptr, ptr + len);
|
|
153
|
+
getI64(addr) {
|
|
154
|
+
return this.i64[addr >> 3];
|
|
87
155
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
return this.f64.subarray(ptr, ptr + len);
|
|
156
|
+
getU64(addr) {
|
|
157
|
+
return this.u64[addr >> 3];
|
|
91
158
|
}
|
|
92
|
-
|
|
93
|
-
return this.
|
|
159
|
+
getF32(addr) {
|
|
160
|
+
return this.f32[addr >> 2];
|
|
94
161
|
}
|
|
95
|
-
|
|
96
|
-
return this.
|
|
162
|
+
getF64(addr) {
|
|
163
|
+
return this.f64[addr >> 3];
|
|
97
164
|
}
|
|
98
|
-
|
|
99
|
-
|
|
165
|
+
setI8(addr, x) {
|
|
166
|
+
this.i8[addr] = x;
|
|
167
|
+
return this;
|
|
100
168
|
}
|
|
101
|
-
|
|
102
|
-
|
|
169
|
+
setU8(addr, x) {
|
|
170
|
+
this.u8[addr] = x;
|
|
171
|
+
return this;
|
|
103
172
|
}
|
|
104
|
-
|
|
105
|
-
|
|
173
|
+
setI16(addr, x) {
|
|
174
|
+
this.i16[addr >> 1] = x;
|
|
175
|
+
return this;
|
|
106
176
|
}
|
|
107
|
-
|
|
108
|
-
|
|
177
|
+
setU16(addr, x) {
|
|
178
|
+
this.u16[addr >> 1] = x;
|
|
179
|
+
return this;
|
|
109
180
|
}
|
|
110
|
-
|
|
111
|
-
|
|
181
|
+
setI32(addr, x) {
|
|
182
|
+
this.i32[addr >> 2] = x;
|
|
183
|
+
return this;
|
|
112
184
|
}
|
|
113
|
-
|
|
114
|
-
|
|
185
|
+
setU32(addr, x) {
|
|
186
|
+
this.u32[addr >> 2] = x;
|
|
187
|
+
return this;
|
|
115
188
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
return this
|
|
189
|
+
setI64(addr, x) {
|
|
190
|
+
this.i64[addr >> 3] = x;
|
|
191
|
+
return this;
|
|
119
192
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
193
|
+
setU64(addr, x) {
|
|
194
|
+
this.u64[addr >> 3] = x;
|
|
195
|
+
return this;
|
|
196
|
+
}
|
|
197
|
+
setF32(addr, x) {
|
|
198
|
+
this.f32[addr >> 2] = x;
|
|
199
|
+
return this;
|
|
200
|
+
}
|
|
201
|
+
setF64(addr, x) {
|
|
202
|
+
this.f64[addr >> 3] = x;
|
|
203
|
+
return this;
|
|
204
|
+
}
|
|
205
|
+
getI8Array(addr, len) {
|
|
206
|
+
return this.i8.subarray(addr, addr + len);
|
|
207
|
+
}
|
|
208
|
+
getU8Array(addr, len) {
|
|
209
|
+
return this.u8.subarray(addr, addr + len);
|
|
210
|
+
}
|
|
211
|
+
getI16Array(addr, len) {
|
|
212
|
+
addr >>= 1;
|
|
213
|
+
return this.i16.subarray(addr, addr + len);
|
|
214
|
+
}
|
|
215
|
+
getU16Array(addr, len) {
|
|
216
|
+
addr >>= 1;
|
|
217
|
+
return this.u16.subarray(addr, addr + len);
|
|
218
|
+
}
|
|
219
|
+
getI32Array(addr, len) {
|
|
220
|
+
addr >>= 2;
|
|
221
|
+
return this.i32.subarray(addr, addr + len);
|
|
222
|
+
}
|
|
223
|
+
getU32Array(addr, len) {
|
|
224
|
+
addr >>= 2;
|
|
225
|
+
return this.u32.subarray(addr, addr + len);
|
|
226
|
+
}
|
|
227
|
+
getI64Array(addr, len) {
|
|
228
|
+
addr >>= 3;
|
|
229
|
+
return this.i64.subarray(addr, addr + len);
|
|
125
230
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
231
|
+
getU64Array(addr, len) {
|
|
232
|
+
addr >>= 3;
|
|
233
|
+
return this.u64.subarray(addr, addr + len);
|
|
234
|
+
}
|
|
235
|
+
getF32Array(addr, len) {
|
|
236
|
+
addr >>= 2;
|
|
237
|
+
return this.f32.subarray(addr, addr + len);
|
|
238
|
+
}
|
|
239
|
+
getF64Array(addr, len) {
|
|
240
|
+
addr >>= 3;
|
|
241
|
+
return this.f64.subarray(addr, addr + len);
|
|
242
|
+
}
|
|
243
|
+
setI8Array(addr, buf) {
|
|
244
|
+
this.i8.set(buf, addr);
|
|
245
|
+
return this;
|
|
246
|
+
}
|
|
247
|
+
setU8Array(addr, buf) {
|
|
248
|
+
this.u8.set(buf, addr);
|
|
249
|
+
return this;
|
|
250
|
+
}
|
|
251
|
+
setI16Array(addr, buf) {
|
|
252
|
+
this.i16.set(buf, addr >> 1);
|
|
253
|
+
return this;
|
|
254
|
+
}
|
|
255
|
+
setU16Array(addr, buf) {
|
|
256
|
+
this.u16.set(buf, addr >> 1);
|
|
257
|
+
return this;
|
|
258
|
+
}
|
|
259
|
+
setI32Array(addr, buf) {
|
|
260
|
+
this.i32.set(buf, addr >> 2);
|
|
261
|
+
return this;
|
|
262
|
+
}
|
|
263
|
+
setU32Array(addr, buf) {
|
|
264
|
+
this.u32.set(buf, addr >> 2);
|
|
265
|
+
return this;
|
|
266
|
+
}
|
|
267
|
+
setI64Array(addr, buf) {
|
|
268
|
+
this.i64.set(buf, addr >> 3);
|
|
269
|
+
return this;
|
|
270
|
+
}
|
|
271
|
+
setU64Array(addr, buf) {
|
|
272
|
+
this.u64.set(buf, addr >> 3);
|
|
273
|
+
return this;
|
|
274
|
+
}
|
|
275
|
+
setF32Array(addr, buf) {
|
|
276
|
+
this.f32.set(buf, addr >> 2);
|
|
277
|
+
return this;
|
|
278
|
+
}
|
|
279
|
+
setF64Array(addr, buf) {
|
|
280
|
+
this.f64.set(buf, addr >> 3);
|
|
281
|
+
return this;
|
|
282
|
+
}
|
|
283
|
+
getString(addr, len = 0) {
|
|
284
|
+
return this.utf8Decoder.decode(this.u8.subarray(addr, len > 0 ? addr + len : this.u8.indexOf(0, addr)));
|
|
285
|
+
}
|
|
286
|
+
setString(str, addr, maxBytes, terminate = true) {
|
|
287
|
+
maxBytes = Math.min(maxBytes, this.u8.length - addr);
|
|
288
|
+
const len = this.utf8Encoder.encodeInto(str, this.u8.subarray(addr, addr + maxBytes)).written;
|
|
289
|
+
if (len != null && len < maxBytes + (terminate ? 0 : 1)) {
|
|
290
|
+
illegalArgs(`error writing string to 0x${U32(addr)}`);
|
|
291
|
+
}
|
|
130
292
|
if (terminate) {
|
|
131
|
-
this.u8[
|
|
293
|
+
this.u8[addr + len] = 0;
|
|
132
294
|
return len + 1;
|
|
133
295
|
}
|
|
134
296
|
return len;
|
|
135
297
|
}
|
|
298
|
+
getElementById(addr, len = 0) {
|
|
299
|
+
const id = this.getString(addr, len);
|
|
300
|
+
const el = document.getElementById(id);
|
|
301
|
+
el == null && illegalArgs(`missing DOM element #${id}`);
|
|
302
|
+
return el;
|
|
303
|
+
}
|
|
136
304
|
}
|
package/dev/custom.zig
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Import JS core API
|
|
2
|
+
const js = @import("wasmapi");
|
|
3
|
+
|
|
4
|
+
/// Fill vec2 with random values
|
|
5
|
+
extern fn custom_randomVec2(addr: usize) void;
|
|
6
|
+
|
|
7
|
+
export fn test_random_vec2() void {
|
|
8
|
+
var foo = [2]f32{ 0, 0 };
|
|
9
|
+
js.printF32Array(foo[0..]);
|
|
10
|
+
custom_randomVec2(@ptrToInt(&foo));
|
|
11
|
+
js.printF32Array(foo[0..]);
|
|
12
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
const js = @import("wasmapi");
|
|
2
|
+
const std = @import("std");
|
|
3
|
+
|
|
4
|
+
const Foo = struct {
|
|
5
|
+
pos: [2]f32,
|
|
6
|
+
col: [3]f32,
|
|
7
|
+
speed: u8,
|
|
8
|
+
acc: u16,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
fn writeU32(buf: [*]u8, i: u32, x: u32) void {
|
|
12
|
+
buf[i] = @intCast(u8, x & 0xff);
|
|
13
|
+
buf[i + 1] = @intCast(u8, x >> 8 & 0xff);
|
|
14
|
+
buf[i + 2] = @intCast(u8, x >> 16 & 0xff);
|
|
15
|
+
buf[i + 3] = @intCast(u8, x >> 24);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const FieldType = enum(u8) {
|
|
19
|
+
I8,
|
|
20
|
+
U8,
|
|
21
|
+
I16,
|
|
22
|
+
U16,
|
|
23
|
+
I32,
|
|
24
|
+
U32,
|
|
25
|
+
F32,
|
|
26
|
+
F64,
|
|
27
|
+
|
|
28
|
+
pub fn fromTypeInfo(comptime info: std.builtin.TypeInfo) FieldType {
|
|
29
|
+
if (info == .Int) {
|
|
30
|
+
const bits = info.Int.bits;
|
|
31
|
+
if (!(bits == 8 or bits == 16 or bits == 32)) {
|
|
32
|
+
@compileError("unsupported int type (only 8, 16, 32)");
|
|
33
|
+
}
|
|
34
|
+
if (info.Int.signedness == .signed) {
|
|
35
|
+
return switch (bits) {
|
|
36
|
+
8 => .I8,
|
|
37
|
+
16 => .I16,
|
|
38
|
+
32 => .I32,
|
|
39
|
+
else => unreachable,
|
|
40
|
+
};
|
|
41
|
+
} else {
|
|
42
|
+
return switch (bits) {
|
|
43
|
+
8 => .U8,
|
|
44
|
+
16 => .U16,
|
|
45
|
+
32 => .U32,
|
|
46
|
+
else => unreachable,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
} else if (info == .Float) {
|
|
50
|
+
return switch (info.Float.bits) {
|
|
51
|
+
32 => .F32,
|
|
52
|
+
64 => .F64,
|
|
53
|
+
else => @compileError("unsupported float type (only f32, f64)"),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
@compileError("unsupported field type");
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// int
|
|
61
|
+
// float
|
|
62
|
+
// ptr
|
|
63
|
+
// array
|
|
64
|
+
// slice
|
|
65
|
+
|
|
66
|
+
// 8
|
|
67
|
+
// 16
|
|
68
|
+
// 32
|
|
69
|
+
// 64
|
|
70
|
+
|
|
71
|
+
const Field = packed struct {
|
|
72
|
+
name: [15]u8 = [_]u8{0} ** 15,
|
|
73
|
+
tag: FieldType = .U8,
|
|
74
|
+
offset: u32,
|
|
75
|
+
len: u32 = 0,
|
|
76
|
+
|
|
77
|
+
pub fn fromTypeInfo(comptime T: type, comptime field: std.builtin.TypeInfo.StructField) Field {
|
|
78
|
+
const finfo = @typeInfo(field.field_type);
|
|
79
|
+
var ftype: FieldType = .U8;
|
|
80
|
+
var flen = 0;
|
|
81
|
+
if (!(finfo == .Int or finfo == .Float or finfo == .Array)) {
|
|
82
|
+
@compileError("unsupported field type: " ++ @typeName(field.field_type));
|
|
83
|
+
}
|
|
84
|
+
if (finfo == .Array) {
|
|
85
|
+
const cinfo = @typeInfo(finfo.Array.child);
|
|
86
|
+
if (!(cinfo == .Int or cinfo == .Float)) {
|
|
87
|
+
@compileError("unsupported field array type: " ++ @typeName(field.field_type));
|
|
88
|
+
}
|
|
89
|
+
ftype = FieldType.fromTypeInfo(cinfo);
|
|
90
|
+
flen = finfo.Array.len;
|
|
91
|
+
} else {
|
|
92
|
+
ftype = FieldType.fromTypeInfo(finfo);
|
|
93
|
+
}
|
|
94
|
+
var res: Field = .{
|
|
95
|
+
.tag = ftype,
|
|
96
|
+
.offset = @offsetOf(T, field.name),
|
|
97
|
+
.len = flen,
|
|
98
|
+
};
|
|
99
|
+
const len = @minimum(14, field.name.len);
|
|
100
|
+
std.mem.copy(u8, res.name[0..len], field.name[0..len]);
|
|
101
|
+
return res;
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
fn writeTypeInfo(comptime T: type) []u8 {
|
|
106
|
+
const fields = @typeInfo(T).Struct.fields;
|
|
107
|
+
const fsize = @sizeOf(Field);
|
|
108
|
+
var buf: [fields.len * fsize + 4]u8 = undefined;
|
|
109
|
+
var i = 4;
|
|
110
|
+
writeU32(&buf, 0, fields.len);
|
|
111
|
+
for (fields) |field| {
|
|
112
|
+
var f = Field.fromTypeInfo(T, field);
|
|
113
|
+
std.mem.copy(
|
|
114
|
+
u8,
|
|
115
|
+
buf[i .. i + fsize],
|
|
116
|
+
@ptrCast(*[fsize]u8, &f)[0..],
|
|
117
|
+
);
|
|
118
|
+
i += fsize;
|
|
119
|
+
}
|
|
120
|
+
return buf[0..];
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export var Foo__info = writeTypeInfo(Foo);
|
|
124
|
+
export var Bar__info = writeTypeInfo(struct { x: i16, y: i16 });
|
|
125
|
+
|
|
126
|
+
export var U64: u64 = 0xdecafbadcafebabe;
|
|
127
|
+
export var I64: i64 = -0x8000000000000000;
|
|
128
|
+
|
|
129
|
+
export fn foo() void {
|
|
130
|
+
js.printI64(I64);
|
|
131
|
+
js.printU64(U64);
|
|
132
|
+
js.printI64Array(&[_]i64{ I64, I64 });
|
|
133
|
+
js.printU32(@truncate(u32, U64 >> 32));
|
|
134
|
+
js.printU32Hex(@truncate(u32, U64 >> 32));
|
|
135
|
+
}
|
package/dev/hello.zig
CHANGED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const std = @import("std");
|
|
2
|
+
/// Zig version. When writing code that supports multiple versions of Zig, prefer
|
|
3
|
+
/// feature detection (i.e. with `@hasDecl` or `@hasField`) over version checks.
|
|
4
|
+
pub const zig_version = std.SemanticVersion.parse("0.10.0-dev.3034+6fab6c3e4") catch unreachable;
|
|
5
|
+
pub const zig_backend = std.builtin.CompilerBackend.stage1;
|
|
6
|
+
/// Temporary until self-hosted supports the `cpu.arch` value.
|
|
7
|
+
pub const stage2_arch: std.Target.Cpu.Arch = .wasm32;
|
|
8
|
+
|
|
9
|
+
pub const output_mode = std.builtin.OutputMode.Lib;
|
|
10
|
+
pub const link_mode = std.builtin.LinkMode.Dynamic;
|
|
11
|
+
pub const is_test = false;
|
|
12
|
+
pub const single_threaded = true;
|
|
13
|
+
pub const abi = std.Target.Abi.musl;
|
|
14
|
+
pub const cpu: std.Target.Cpu = .{
|
|
15
|
+
.arch = .wasm32,
|
|
16
|
+
.model = &std.Target.wasm.cpu.generic,
|
|
17
|
+
.features = std.Target.wasm.featureSet(&[_]std.Target.wasm.Feature{
|
|
18
|
+
}),
|
|
19
|
+
};
|
|
20
|
+
pub const os = std.Target.Os{
|
|
21
|
+
.tag = .freestanding,
|
|
22
|
+
.version_range = .{ .none = {} },
|
|
23
|
+
};
|
|
24
|
+
pub const target = std.Target{
|
|
25
|
+
.cpu = cpu,
|
|
26
|
+
.os = os,
|
|
27
|
+
.abi = abi,
|
|
28
|
+
};
|
|
29
|
+
pub const object_format = std.Target.ObjectFormat.wasm;
|
|
30
|
+
pub const mode = std.builtin.Mode.ReleaseSmall;
|
|
31
|
+
pub const link_libc = false;
|
|
32
|
+
pub const link_libcpp = false;
|
|
33
|
+
pub const have_error_return_tracing = false;
|
|
34
|
+
pub const valgrind_support = false;
|
|
35
|
+
pub const sanitize_thread = false;
|
|
36
|
+
pub const position_independent_code = true;
|
|
37
|
+
pub const position_independent_executable = false;
|
|
38
|
+
pub const strip_debug_info = true;
|
|
39
|
+
pub const code_model = std.builtin.CodeModel.default;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const std = @import("std");
|
|
2
|
+
/// Zig version. When writing code that supports multiple versions of Zig, prefer
|
|
3
|
+
/// feature detection (i.e. with `@hasDecl` or `@hasField`) over version checks.
|
|
4
|
+
pub const zig_version = std.SemanticVersion.parse("0.10.0-dev.3034+6fab6c3e4") catch unreachable;
|
|
5
|
+
pub const zig_backend = std.builtin.CompilerBackend.stage1;
|
|
6
|
+
/// Temporary until self-hosted supports the `cpu.arch` value.
|
|
7
|
+
pub const stage2_arch: std.Target.Cpu.Arch = .wasm32;
|
|
8
|
+
|
|
9
|
+
pub const output_mode = std.builtin.OutputMode.Lib;
|
|
10
|
+
pub const link_mode = std.builtin.LinkMode.Dynamic;
|
|
11
|
+
pub const is_test = false;
|
|
12
|
+
pub const single_threaded = true;
|
|
13
|
+
pub const abi = std.Target.Abi.musl;
|
|
14
|
+
pub const cpu: std.Target.Cpu = .{
|
|
15
|
+
.arch = .wasm32,
|
|
16
|
+
.model = &std.Target.wasm.cpu.generic,
|
|
17
|
+
.features = std.Target.wasm.featureSet(&[_]std.Target.wasm.Feature{
|
|
18
|
+
}),
|
|
19
|
+
};
|
|
20
|
+
pub const os = std.Target.Os{
|
|
21
|
+
.tag = .freestanding,
|
|
22
|
+
.version_range = .{ .none = {} },
|
|
23
|
+
};
|
|
24
|
+
pub const target = std.Target{
|
|
25
|
+
.cpu = cpu,
|
|
26
|
+
.os = os,
|
|
27
|
+
.abi = abi,
|
|
28
|
+
};
|
|
29
|
+
pub const object_format = std.Target.ObjectFormat.wasm;
|
|
30
|
+
pub const mode = std.builtin.Mode.ReleaseSmall;
|
|
31
|
+
pub const link_libc = false;
|
|
32
|
+
pub const link_libcpp = false;
|
|
33
|
+
pub const have_error_return_tracing = false;
|
|
34
|
+
pub const valgrind_support = false;
|
|
35
|
+
pub const sanitize_thread = false;
|
|
36
|
+
pub const position_independent_code = true;
|
|
37
|
+
pub const position_independent_executable = false;
|
|
38
|
+
pub const strip_debug_info = true;
|
|
39
|
+
pub const code_model = std.builtin.CodeModel.default;
|