Offload functions to worker threads with shared memory primitives for Node.js.
1import { describe, it } from 'node:test';
2import assert from 'node:assert/strict';
3import { workers, transfer } from 'moroutine';
4import { sumBuffer, sumUint8, makeBuffer } from './fixtures/transfer.ts';
5
6describe('transfer', () => {
7 it('transfers an ArrayBuffer to a worker (zero-copy)', async () => {
8 const buf = new ArrayBuffer(4);
9 const view = new Uint8Array(buf);
10 view[0] = 1;
11 view[1] = 2;
12 view[2] = 3;
13 view[3] = 4;
14
15 const run = workers(1);
16 try {
17 const sum = await run(sumBuffer(transfer(buf)));
18 assert.equal(sum, 10);
19 // Original buffer should be detached after transfer
20 assert.equal(buf.byteLength, 0);
21 } finally {
22 run[Symbol.dispose]();
23 }
24 });
25
26 it('transfers a Uint8Array to a worker via its buffer', async () => {
27 const arr = new Uint8Array([5, 10, 15, 20]);
28 const originalBuffer = arr.buffer;
29
30 const run = workers(1);
31 try {
32 const sum = await run(sumUint8(transfer(arr)));
33 assert.equal(sum, 50);
34 // Underlying buffer should be detached after transfer
35 assert.equal(originalBuffer.byteLength, 0);
36 } finally {
37 run[Symbol.dispose]();
38 }
39 });
40
41 it('auto-transfers return values from worker (zero-copy)', async () => {
42 const run = workers(1);
43 try {
44 const buf = await run(makeBuffer(4));
45 const view = new Uint8Array(buf);
46 assert.equal(buf.byteLength, 4);
47 assert.deepEqual([...view], [1, 2, 3, 4]);
48 } finally {
49 run[Symbol.dispose]();
50 }
51 });
52
53 it('without transfer, buffer is copied (not detached)', async () => {
54 const buf = new ArrayBuffer(4);
55 const view = new Uint8Array(buf);
56 view[0] = 1;
57 view[1] = 2;
58 view[2] = 3;
59 view[3] = 4;
60
61 const run = workers(1);
62 try {
63 const sum = await run(sumBuffer(buf));
64 assert.equal(sum, 10);
65 // Original buffer should NOT be detached (it was copied)
66 assert.equal(buf.byteLength, 4);
67 } finally {
68 run[Symbol.dispose]();
69 }
70 });
71});