Offload functions to worker threads with shared memory primitives for Node.js.
1import { registerSync } from './reconstruct.ts';
2
3export class Int32Atomic {
4 static readonly byteSize = 4;
5 static readonly byteAlignment = 4;
6 private readonly view: Int32Array;
7
8 constructor(buffer?: SharedArrayBuffer, byteOffset?: number) {
9 const buf = buffer ?? new SharedArrayBuffer(4);
10 const offset = byteOffset ?? 0;
11 this.view = new Int32Array(buf, offset, 1);
12 }
13
14 load(): number {
15 return Atomics.load(this.view, 0);
16 }
17
18 store(value: number): void {
19 Atomics.store(this.view, 0, value);
20 }
21
22 add(value: number): number {
23 return Atomics.add(this.view, 0, value);
24 }
25
26 sub(value: number): number {
27 return Atomics.sub(this.view, 0, value);
28 }
29
30 and(value: number): number {
31 return Atomics.and(this.view, 0, value);
32 }
33
34 or(value: number): number {
35 return Atomics.or(this.view, 0, value);
36 }
37
38 xor(value: number): number {
39 return Atomics.xor(this.view, 0, value);
40 }
41
42 exchange(value: number): number {
43 return Atomics.exchange(this.view, 0, value);
44 }
45
46 compareExchange(expected: number, replacement: number): number {
47 return Atomics.compareExchange(this.view, 0, expected, replacement);
48 }
49
50 /**
51 * Parks asynchronously until the slot's value differs from `expected` or the optional timeout elapses.
52 * Returns `'not-equal'` synchronously (no await) if the slot already holds a different value.
53 * @param expected - Value to wait against; wake when the slot's value is observed to differ.
54 * @param timeoutMs - Optional timeout in milliseconds. Defaults to Infinity.
55 * @returns `'ok'` if woken by a notify, `'not-equal'` if the value already differed, `'timed-out'` if the timeout elapsed.
56 */
57 async waitAsync(expected: number, timeoutMs?: number): Promise<'ok' | 'not-equal' | 'timed-out'> {
58 const r = Atomics.waitAsync(this.view, 0, expected, timeoutMs);
59 return r.async ? await r.value : r.value;
60 }
61
62 /**
63 * Wakes up to `count` waiters on this slot. Returns the number actually woken.
64 * @param count - Maximum number of waiters to wake. Defaults to Infinity.
65 */
66 notify(count: number = Infinity): number {
67 return Atomics.notify(this.view, 0, count);
68 }
69
70 [Symbol.for('moroutine.shared')](): { tag: string; buffer: SharedArrayBuffer; byteOffset: number } {
71 return { tag: 'Int32Atomic', buffer: this.view.buffer as SharedArrayBuffer, byteOffset: this.view.byteOffset };
72 }
73}
74
75registerSync('Int32Atomic', Int32Atomic);