wasm-bindgen-lite 0.1.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.
@@ -0,0 +1,423 @@
1
+ import { readFileSync, writeFileSync, mkdirSync } from 'node:fs'
2
+ import { join } from 'node:path'
3
+ import { fileURLToPath } from 'node:url'
4
+
5
+ const UTIL_PATH = fileURLToPath(new URL('../js/util.js', import.meta.url))
6
+
7
+ function createCore({ exportsList, autoInit, stream }) {
8
+ const needsEnsure = autoInit === 'lazy'
9
+ const toBytesHelper = `function toBytes(input) {
10
+ if (input instanceof Uint8Array) return input;
11
+ if (ArrayBuffer.isView(input)) {
12
+ return new Uint8Array(input.buffer, input.byteOffset, input.byteLength);
13
+ }
14
+ if (input instanceof ArrayBuffer) return new Uint8Array(input);
15
+ throw new TypeError("Expected a TypedArray or ArrayBuffer");
16
+ }
17
+ `
18
+ const scalarSizeHelper = `function scalarSize(type) {
19
+ switch (type) {
20
+ case "f64": return 8;
21
+ case "f32":
22
+ case "i32":
23
+ case "u32": return 4;
24
+ case "i16":
25
+ case "u16": return 2;
26
+ case "i8":
27
+ case "u8": return 1;
28
+ case "u32_array":
29
+ case "i32_array":
30
+ case "f32_array": return 1024 * 1024; // Default large buffer for arrays, or we can improve this
31
+ default: return 0;
32
+ }
33
+ }
34
+ `
35
+ const decodeHelper = `function decodeReturn(view, type) {
36
+ switch (type) {
37
+ case "f32": return view.getFloat32(0, true);
38
+ case "f64": return view.getFloat64(0, true);
39
+ case "i32": return view.getInt32(0, true);
40
+ case "u32": return view.getUint32(0, true);
41
+ case "i16": return view.getInt16(0, true);
42
+ case "u16": return view.getUint16(0, true);
43
+ case "i8": return view.getInt8(0);
44
+ case "u8": return view.getUint8(0);
45
+ case "u32_array": return new Uint32Array(view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength));
46
+ case "i32_array": return new Int32Array(view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength));
47
+ case "f32_array": return new Float32Array(view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength));
48
+ default: return null;
49
+ }
50
+ }
51
+ `
52
+
53
+ const wrappers = exportsList
54
+ .map(({ abi, name, return: retType, reuseBuffer }) => {
55
+ const returnType = retType || 'bytes'
56
+ const fnName = name || abi
57
+ const outSizeExpr =
58
+ returnType === 'bytes'
59
+ ? 'Math.max(len, 4)'
60
+ : `(scalarSize('${returnType}') || 4)`
61
+
62
+ const stateVars = reuseBuffer
63
+ ? `let _${fnName}_in = { ptr: 0, len: 0 };
64
+ let _${fnName}_out = { ptr: 0, len: 0 };`
65
+ : ''
66
+
67
+ const allocIn = reuseBuffer
68
+ ? `if (_${fnName}_in.len < len) {
69
+ if (_${fnName}_in.ptr) free(_${fnName}_in.ptr, _${fnName}_in.len);
70
+ _${fnName}_in.ptr = alloc(len);
71
+ _${fnName}_in.len = len;
72
+ }
73
+ const inPtr = _${fnName}_in.ptr;`
74
+ : `const inPtr = alloc(len);`
75
+
76
+ const allocOut = reuseBuffer
77
+ ? `if (_${fnName}_out.len < outLen) {
78
+ if (_${fnName}_out.ptr) free(_${fnName}_out.ptr, _${fnName}_out.len);
79
+ _${fnName}_out.ptr = alloc(outLen);
80
+ _${fnName}_out.len = outLen;
81
+ }
82
+ const outPtr = _${fnName}_out.ptr;`
83
+ : `const outPtr = alloc(outLen);`
84
+
85
+ const freeIn = reuseBuffer ? '' : `free(inPtr, len);`
86
+ const freeOut = reuseBuffer ? '' : `free(outPtr, outLen);`
87
+
88
+ const body = `
89
+ if (!_inst) throw new Error("WASM instance not initialized");
90
+ const view = toBytes(input);
91
+ const len = view.byteLength;
92
+ ${allocIn}
93
+ memoryU8().set(view, inPtr);
94
+ const outLen = ${outSizeExpr};
95
+ ${allocOut}
96
+ const written = _inst.exports.${abi}(
97
+ inPtr, len,
98
+ outPtr, outLen
99
+ );
100
+ if (written < 0) {
101
+ ${reuseBuffer ? '' : `free(inPtr, len); free(outPtr, outLen);`}
102
+ throw new Error("${abi} failed: " + written);
103
+ }
104
+ ${
105
+ returnType === 'bytes'
106
+ ? `const result = memoryU8().slice(outPtr, outPtr + written);`
107
+ : `const retView = new DataView(memoryU8().buffer, outPtr, written);
108
+ const ret = decodeReturn(retView, "${returnType}");`
109
+ }
110
+ ${freeIn}
111
+ ${freeOut}
112
+ ${returnType === 'bytes' ? 'return result;' : 'return ret;'}`
113
+
114
+ const wrapper = needsEnsure
115
+ ? `async function ${fnName}(input) { await ensureReady(); ${body} }`
116
+ : `function ${fnName}(input) { ${body} }`
117
+
118
+ return `${stateVars}\n${wrapper}\nexport { ${fnName} };`
119
+ })
120
+ .join('\n\n')
121
+
122
+ const streamHelper = stream?.enable
123
+ ? `
124
+ const __exports = { ${exportsList.map(({ name, abi }) => `${name || abi}: ${name || abi}`).join(', ')} };
125
+
126
+ export function createTransformStream(fnName = "${stream.export}") {
127
+ const fn = __exports[fnName];
128
+ if (!fn) throw new Error("Unknown export for streaming: " + fnName);
129
+
130
+ ${
131
+ stream.delimiter !== null
132
+ ? `let buffer = new Uint8Array(0);
133
+ const delimiter = ${stream.delimiter};`
134
+ : ''
135
+ }
136
+
137
+ return new TransformStream({
138
+ async transform(chunk, controller) {
139
+ const bytes = toBytes(chunk);
140
+ const processed = ${needsEnsure ? 'await fn(bytes)' : 'fn(bytes)'};
141
+
142
+ ${
143
+ stream.delimiter !== null
144
+ ? `// Split and buffer
145
+ const combined = new Uint8Array(buffer.length + processed.length);
146
+ combined.set(buffer, 0);
147
+ combined.set(processed, buffer.length);
148
+
149
+ let start = 0;
150
+ for (let i = 0; i < combined.length; i += 1) {
151
+ if (combined[i] === delimiter) {
152
+ controller.enqueue(combined.subarray(start, i));
153
+ start = i + 1;
154
+ }
155
+ }
156
+ buffer = combined.slice(start);`
157
+ : 'controller.enqueue(processed);'
158
+ }
159
+ }${
160
+ stream.delimiter !== null
161
+ ? `,
162
+ flush(controller) {
163
+ if (buffer.length) controller.enqueue(buffer);
164
+ }`
165
+ : ''
166
+ }
167
+ });
168
+ }
169
+ `
170
+ : ''
171
+
172
+ const ensure = needsEnsure
173
+ ? `
174
+ let _ready = null;
175
+ export function registerInit(fn) {
176
+ _initFn = fn;
177
+ }
178
+
179
+ async function ensureReady() {
180
+ if (_ready) return _ready;
181
+ if (!_initFn) throw new Error("init not registered");
182
+ _ready = _initFn();
183
+ return _ready;
184
+ }
185
+ `
186
+ : `
187
+ export function registerInit(fn) {
188
+ _initFn = fn;
189
+ }
190
+ `
191
+
192
+ return `let _inst = null;
193
+ let _memU8 = null;
194
+ let _initFn = null;
195
+
196
+ function refreshViews() {
197
+ _memU8 = new Uint8Array(_inst.exports.memory.buffer);
198
+ }
199
+
200
+ export function setInstance(instance) {
201
+ _inst = instance;
202
+ refreshViews();
203
+ }
204
+
205
+ export function wasmExports() {
206
+ return _inst.exports;
207
+ }
208
+
209
+ ${ensure}
210
+
211
+ export function memoryU8() {
212
+ if (_memU8 && _memU8.buffer !== _inst.exports.memory.buffer) refreshViews();
213
+ return _memU8;
214
+ }
215
+
216
+ export function alloc(len) {
217
+ return _inst.exports.alloc_bytes(len) >>> 0;
218
+ }
219
+
220
+ export function free(ptr, len) {
221
+ _inst.exports.free_bytes(ptr >>> 0, len >>> 0);
222
+ }
223
+
224
+ ${wrappers}
225
+ ${scalarSizeHelper}
226
+ ${decodeHelper}
227
+ ${toBytesHelper}
228
+ ${streamHelper}
229
+ `
230
+ }
231
+
232
+ function createBrowserLoader({ name, autoInit, customJs, wasmDelivery }) {
233
+ const eager =
234
+ autoInit === 'eager'
235
+ ? '\nregisterInit(init);\ninit();'
236
+ : '\nregisterInit(init);'
237
+ const exportFrom = customJs ? './custom.js' : './core.js'
238
+
239
+ let simdUrl, baseUrl
240
+ if (wasmDelivery.type === 'jsdelivr') {
241
+ const pkg = wasmDelivery.package
242
+ const ver = wasmDelivery.version
243
+ simdUrl = `https://cdn.jsdelivr.net/npm/${pkg}@${ver}/dist/wasm/${name}.simd.wasm`
244
+ baseUrl = `https://cdn.jsdelivr.net/npm/${pkg}@${ver}/dist/wasm/${name}.base.wasm`
245
+ } else {
246
+ simdUrl = `new URL("./wasm/${name}.simd.wasm", import.meta.url)`
247
+ baseUrl = `new URL("./wasm/${name}.base.wasm", import.meta.url)`
248
+ }
249
+
250
+ return `import { setInstance, registerInit } from "./core.js";
251
+ import { instantiateWithFallback } from "./util.js";
252
+
253
+ const simdUrl = ${wasmDelivery.type === 'jsdelivr' ? `"${simdUrl}"` : simdUrl};
254
+ const baseUrl = ${wasmDelivery.type === 'jsdelivr' ? `"${baseUrl}"` : baseUrl};
255
+
256
+ let _ready = null;
257
+
258
+ export function init(imports = {}) {
259
+ return (_ready ??= (async () => {
260
+ const [simdRes, baseRes] = await Promise.all([
261
+ fetch(simdUrl),
262
+ fetch(baseUrl)
263
+ ]);
264
+
265
+ const [simdBytes, baseBytes] = await Promise.all([
266
+ simdRes.arrayBuffer(),
267
+ baseRes.arrayBuffer()
268
+ ]);
269
+
270
+ const { instance } = await instantiateWithFallback(simdBytes, baseBytes, imports);
271
+ setInstance(instance);
272
+ })());
273
+ }
274
+ ${eager}
275
+ export * from "${exportFrom}";
276
+ `
277
+ }
278
+
279
+ function createNodeLoader({ name, autoInit, customJs }) {
280
+ const eager =
281
+ autoInit === 'eager'
282
+ ? '\nregisterInit(init);\ninit();'
283
+ : '\nregisterInit(init);'
284
+ const exportFrom = customJs ? './custom.js' : './core.js'
285
+ return `import { readFile } from "node:fs/promises";
286
+ import { fileURLToPath } from "node:url";
287
+ import { setInstance, registerInit } from "./core.js";
288
+ import { instantiateWithFallback } from "./util.js";
289
+
290
+ const simdPath = fileURLToPath(new URL("./wasm/${name}.simd.wasm", import.meta.url));
291
+ const basePath = fileURLToPath(new URL("./wasm/${name}.base.wasm", import.meta.url));
292
+
293
+ let _ready = null;
294
+
295
+ export function init(imports = {}) {
296
+ return (_ready ??= (async () => {
297
+ const [simdBytes, baseBytes] = await Promise.all([
298
+ readFile(simdPath),
299
+ readFile(basePath)
300
+ ]);
301
+ const { instance } = await instantiateWithFallback(simdBytes, baseBytes, imports);
302
+ setInstance(instance);
303
+ })());
304
+ }
305
+ ${eager}
306
+ export * from "${exportFrom}";
307
+ `
308
+ }
309
+
310
+ function createInlineLoader({ name, autoInit, customJs }) {
311
+ const eager =
312
+ autoInit === 'eager'
313
+ ? '\nregisterInit(init);\ninit();'
314
+ : '\nregisterInit(init);'
315
+ const exportFrom = customJs ? './custom.js' : './core.js'
316
+ return `import { wasmBytes as simdBytes } from "./wasm-inline/${name}.simd.wasm.js";
317
+ import { wasmBytes as baseBytes } from "./wasm-inline/${name}.base.wasm.js";
318
+ import { setInstance, registerInit } from "./core.js";
319
+ import { instantiateWithFallback } from "./util.js";
320
+
321
+ let _ready = null;
322
+
323
+ export function init(imports = {}) {
324
+ return (_ready ??= (async () => {
325
+ const { instance } = await instantiateWithFallback(simdBytes, baseBytes, imports);
326
+ setInstance(instance);
327
+ })());
328
+ }
329
+ ${eager}
330
+ export * from "${exportFrom}";
331
+ `
332
+ }
333
+
334
+ function createInlineModule(bytes) {
335
+ return `// auto-generated
336
+ export const wasmBytes = new Uint8Array([${bytes.join(',')}]);
337
+ `
338
+ }
339
+
340
+ function writeInlineModules({
341
+ outDir,
342
+ artifactBaseName,
343
+ baselinePath,
344
+ simdPath,
345
+ }) {
346
+ const inlineDir = join(outDir, 'wasm-inline')
347
+ mkdirSync(inlineDir, { recursive: true })
348
+
349
+ const baseBytes = readFileSync(baselinePath)
350
+ const simdBytes = simdPath ? readFileSync(simdPath) : baseBytes
351
+
352
+ writeFileSync(
353
+ join(inlineDir, `${artifactBaseName}.base.wasm.js`),
354
+ createInlineModule(baseBytes)
355
+ )
356
+ writeFileSync(
357
+ join(inlineDir, `${artifactBaseName}.simd.wasm.js`),
358
+ createInlineModule(simdBytes)
359
+ )
360
+ }
361
+
362
+ export function emitRuntime({
363
+ outDir,
364
+ artifactBaseName,
365
+ emitNode,
366
+ emitBrowser,
367
+ emitInline,
368
+ wasmPaths,
369
+ exportsList,
370
+ autoInit,
371
+ stream,
372
+ customJs,
373
+ wasmDelivery,
374
+ }) {
375
+ mkdirSync(outDir, { recursive: true })
376
+
377
+ if (customJs) {
378
+ const customJsContent = readFileSync(join(process.cwd(), customJs), 'utf8')
379
+ writeFileSync(join(outDir, 'custom.js'), customJsContent)
380
+ }
381
+
382
+ writeFileSync(
383
+ join(outDir, 'core.js'),
384
+ createCore({ exportsList, autoInit, stream })
385
+ )
386
+ writeFileSync(join(outDir, 'util.js'), readFileSync(UTIL_PATH, 'utf8'))
387
+
388
+ if (emitBrowser) {
389
+ writeFileSync(
390
+ join(outDir, 'browser.js'),
391
+ createBrowserLoader({
392
+ name: artifactBaseName,
393
+ autoInit,
394
+ customJs,
395
+ wasmDelivery,
396
+ })
397
+ )
398
+ }
399
+
400
+ if (emitNode) {
401
+ writeFileSync(
402
+ join(outDir, 'node.js'),
403
+ createNodeLoader({ name: artifactBaseName, autoInit, customJs })
404
+ )
405
+ }
406
+
407
+ if (emitInline && wasmPaths.baselinePath) {
408
+ writeFileSync(
409
+ join(outDir, 'browser-inline.js'),
410
+ createInlineLoader({ name: artifactBaseName, autoInit, customJs })
411
+ )
412
+ writeFileSync(
413
+ join(outDir, 'node-inline.js'),
414
+ createInlineLoader({ name: artifactBaseName, autoInit, customJs })
415
+ )
416
+ writeInlineModules({
417
+ outDir,
418
+ artifactBaseName,
419
+ baselinePath: wasmPaths.baselinePath,
420
+ simdPath: wasmPaths.simdPath,
421
+ })
422
+ }
423
+ }
@@ -0,0 +1,79 @@
1
+ import { rmSync, existsSync } from 'node:fs'
2
+ import { loadConfigFromCli, summarizeConfig } from './config.js'
3
+ import { buildArtifacts } from './build.js'
4
+ import { emitRuntime } from './emit.js'
5
+ import { updatePackageJson } from './pkg.js'
6
+
7
+ export async function runBuild(cliOpts) {
8
+ const cfg = loadConfigFromCli(cliOpts)
9
+ console.log('Configuration:', summarizeConfig(cfg))
10
+
11
+ const wasmPaths = buildArtifacts({
12
+ crateDir: cfg.crateDir,
13
+ wasmFileStem: cfg.wasmFileStem,
14
+ artifactBaseName: cfg.artifactBaseName,
15
+ outDir: cfg.outDir,
16
+ targets: cfg.targets,
17
+ release: cfg.release,
18
+ wasmOpt: cfg.wasmOpt,
19
+ })
20
+
21
+ emitRuntime({
22
+ outDir: cfg.outDir,
23
+ artifactBaseName: cfg.artifactBaseName,
24
+ emitNode: cfg.js.emit.node,
25
+ emitBrowser: cfg.js.emit.browser,
26
+ emitInline: cfg.inline && cfg.js.emit.inline,
27
+ wasmPaths,
28
+ exportsList: cfg.exports,
29
+ autoInit: cfg.autoInit,
30
+ stream: cfg.stream,
31
+ customJs: cfg.js.custom,
32
+ wasmDelivery: cfg.wasmDelivery,
33
+ })
34
+
35
+ if (cliOpts.updatePackageJson !== false) {
36
+ updatePackageJson({
37
+ crateDir: cfg.crateDir,
38
+ outDir: cfg.outDir,
39
+ artifactBaseName: cfg.artifactBaseName,
40
+ js: cfg.js,
41
+ inline: cfg.inline,
42
+ })
43
+ }
44
+
45
+ console.log('Build complete:', cfg.outDir)
46
+ }
47
+
48
+ export async function runClean(cliOpts) {
49
+ const cfg = loadConfigFromCli(cliOpts)
50
+ if (existsSync(cfg.outDir)) {
51
+ rmSync(cfg.outDir, { recursive: true, force: true })
52
+ console.log(`Removed ${cfg.outDir}`)
53
+ } else {
54
+ console.log(`Nothing to clean at ${cfg.outDir}`)
55
+ }
56
+ }
57
+
58
+ export function printHelp() {
59
+ const help = `
60
+ wasm-bindgen-lite <command> [options]
61
+
62
+ Commands:
63
+ build Build wasm artifacts and emit JS loaders (default release)
64
+ clean Remove the configured output directory
65
+ help Show this message
66
+
67
+ Options (for build):
68
+ --crate <path> Crate root (default: .)
69
+ --out <path> Output dir (default: dist-wasm-bindgen-lite)
70
+ --config <path> Path to config JSON (default: wasm-bindgen-lite.config.json)
71
+ --release | --debug Toggle cargo profile (default: release)
72
+ --inline | --no-inline Emit inline loaders and byte modules (default: inline)
73
+ --simd | --no-simd Build SIMD variant (default: simd on)
74
+ --wasm-opt | --no-wasm-opt Force enable/disable wasm-opt (default: auto detect)
75
+ --wasm-opt-args "<args>" Extra args, default "-Oz"
76
+ --no-update-package-json Do not modify package.json exports (default: updates if package.json exists)
77
+ `
78
+ console.log(help)
79
+ }
package/src/cli/pkg.js ADDED
@@ -0,0 +1,52 @@
1
+ import { readFileSync, writeFileSync, existsSync } from 'node:fs'
2
+ import { join, relative } from 'node:path'
3
+
4
+ export function updatePackageJson({
5
+ crateDir,
6
+ outDir,
7
+ artifactBaseName,
8
+ js,
9
+ inline,
10
+ }) {
11
+ const pkgPath = join(crateDir, 'package.json')
12
+ if (!existsSync(pkgPath)) return
13
+
14
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'))
15
+ const relOutDir = './' + relative(crateDir, outDir)
16
+
17
+ if (!pkg.exports) pkg.exports = {}
18
+
19
+ const mainExports = {}
20
+ if (js.emit.browser) {
21
+ mainExports.browser = `${relOutDir}/browser.js`
22
+ }
23
+ if (js.emit.node) {
24
+ mainExports.node = `${relOutDir}/node.js`
25
+ if (!mainExports.default) mainExports.default = `${relOutDir}/node.js`
26
+ }
27
+
28
+ if (Object.keys(mainExports).length > 0) {
29
+ pkg.exports['.'] = mainExports
30
+ }
31
+
32
+ if (inline && js.emit.inline) {
33
+ const inlineExports = {}
34
+ if (js.emit.browser) {
35
+ inlineExports.browser = `${relOutDir}/browser-inline.js`
36
+ }
37
+ if (js.emit.node) {
38
+ inlineExports.node = `${relOutDir}/node-inline.js`
39
+ if (!inlineExports.default)
40
+ inlineExports.default = `${relOutDir}/node-inline.js`
41
+ }
42
+ if (Object.keys(inlineExports).length > 0) {
43
+ pkg.exports['./inline'] = inlineExports
44
+ }
45
+ }
46
+
47
+ // Also update main/module/types if they are missing?
48
+ // For now let's just focus on exports as it's the modern way.
49
+
50
+ writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n')
51
+ console.log('Updated package.json exports')
52
+ }
@@ -0,0 +1,19 @@
1
+ import { wasmBytes as simdBytes } from './wasm-inline/mod.simd.wasm.js'
2
+ import { wasmBytes as baseBytes } from './wasm-inline/mod.base.wasm.js'
3
+ import { setInstance } from './core.js'
4
+ import { instantiateWithFallback } from './util.js'
5
+
6
+ let _ready = null
7
+
8
+ export function init(imports = {}) {
9
+ return (_ready ??= (async () => {
10
+ const { instance } = await instantiateWithFallback(
11
+ simdBytes,
12
+ baseBytes,
13
+ imports
14
+ )
15
+ setInstance(instance)
16
+ })())
17
+ }
18
+
19
+ export * from './core.js'
@@ -0,0 +1,30 @@
1
+ import { setInstance } from './core.js'
2
+ import { instantiateWithFallback } from './util.js'
3
+
4
+ const simdUrl = new URL('./wasm/mod.simd.wasm', import.meta.url)
5
+ const baseUrl = new URL('./wasm/mod.base.wasm', import.meta.url)
6
+
7
+ let _ready = null
8
+
9
+ export function init(imports = {}) {
10
+ return (_ready ??= (async () => {
11
+ const [simdRes, baseRes] = await Promise.all([
12
+ fetch(simdUrl),
13
+ fetch(baseUrl),
14
+ ])
15
+
16
+ const [simdBytes, baseBytes] = await Promise.all([
17
+ simdRes.arrayBuffer(),
18
+ baseRes.arrayBuffer(),
19
+ ])
20
+
21
+ const { instance } = await instantiateWithFallback(
22
+ simdBytes,
23
+ baseBytes,
24
+ imports
25
+ )
26
+ setInstance(instance)
27
+ })())
28
+ }
29
+
30
+ export * from './core.js'
package/src/js/core.js ADDED
@@ -0,0 +1,57 @@
1
+ let _inst = null
2
+ let _memU8 = null
3
+
4
+ function refreshViews() {
5
+ _memU8 = new Uint8Array(_inst.exports.memory.buffer)
6
+ }
7
+
8
+ export function setInstance(instance) {
9
+ _inst = instance
10
+ refreshViews()
11
+ }
12
+
13
+ export function memoryU8() {
14
+ // memory can grow, so refresh if needed:
15
+ if (_memU8.buffer !== _inst.exports.memory.buffer) refreshViews()
16
+ return _memU8
17
+ }
18
+
19
+ export function alloc(len) {
20
+ return _inst.exports.alloc_bytes(len) >>> 0
21
+ }
22
+
23
+ export function free(ptr, len) {
24
+ _inst.exports.free_bytes(ptr >>> 0, len >>> 0)
25
+ }
26
+
27
+ /**
28
+ * Example wrapper around the raw ABI
29
+ */
30
+ export function process(inputU8) {
31
+ const inPtr = alloc(inputU8.length)
32
+ memoryU8().set(inputU8, inPtr)
33
+
34
+ const outPtr = alloc(inputU8.length)
35
+ // No need to set outU8 yet, but memory might have grown again
36
+
37
+ const written = _inst.exports.process_bytes(
38
+ inPtr,
39
+ inputU8.length,
40
+ outPtr,
41
+ inputU8.length
42
+ )
43
+
44
+ if (written < 0) {
45
+ free(inPtr, inputU8.length)
46
+ free(outPtr, inputU8.length)
47
+ throw new Error(`process_bytes failed: ${written}`)
48
+ }
49
+
50
+ // Refresh view again because memory might have grown during alloc
51
+ const result = memoryU8().slice(outPtr, outPtr + written)
52
+
53
+ free(inPtr, inputU8.length)
54
+ free(outPtr, inputU8.length)
55
+
56
+ return result
57
+ }
@@ -0,0 +1,19 @@
1
+ import { wasmBytes as simdBytes } from './wasm-inline/mod.simd.wasm.js'
2
+ import { wasmBytes as baseBytes } from './wasm-inline/mod.base.wasm.js'
3
+ import { setInstance } from './core.js'
4
+ import { instantiateWithFallback } from './util.js'
5
+
6
+ let _ready = null
7
+
8
+ export function init(imports = {}) {
9
+ return (_ready ??= (async () => {
10
+ const { instance } = await instantiateWithFallback(
11
+ simdBytes,
12
+ baseBytes,
13
+ imports
14
+ )
15
+ setInstance(instance)
16
+ })())
17
+ }
18
+
19
+ export * from './core.js'
package/src/js/node.js ADDED
@@ -0,0 +1,26 @@
1
+ import { readFile } from 'node:fs/promises'
2
+ import { fileURLToPath } from 'node:url'
3
+ import { setInstance } from './core.js'
4
+ import { instantiateWithFallback } from './util.js'
5
+
6
+ const simdPath = fileURLToPath(new URL('./wasm/mod.simd.wasm', import.meta.url))
7
+ const basePath = fileURLToPath(new URL('./wasm/mod.base.wasm', import.meta.url))
8
+
9
+ let _ready = null
10
+
11
+ export function init(imports = {}) {
12
+ return (_ready ??= (async () => {
13
+ const [simdBytes, baseBytes] = await Promise.all([
14
+ readFile(simdPath),
15
+ readFile(basePath),
16
+ ])
17
+ const { instance } = await instantiateWithFallback(
18
+ simdBytes,
19
+ baseBytes,
20
+ imports
21
+ )
22
+ setInstance(instance)
23
+ })())
24
+ }
25
+
26
+ export * from './core.js'