Offload functions to worker threads with shared memory primitives for Node.js.
8
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: descriptor functions for all shared primitives, atomics, and locks

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Devin Ivy a6325255 34770271

+160
+5
src/index.ts
··· 31 31 slab, 32 32 SharedStruct, 33 33 } from './shared/index.ts'; 34 + export { 35 + int8, uint8, int16, uint16, int32, uint32, int64, uint64, bool, 36 + int8atomic, uint8atomic, int16atomic, uint16atomic, int32atomic, uint32atomic, int64atomic, uint64atomic, boolatomic, 37 + mutex, rwlock, 38 + } from './shared/index.ts';
+59
src/shared/descriptors.ts
··· 1 + import { Int8 } from './int8.ts'; 2 + import { Uint8 } from './uint8.ts'; 3 + import { Int16 } from './int16.ts'; 4 + import { Uint16 } from './uint16.ts'; 5 + import { Int32 } from './int32.ts'; 6 + import { Uint32 } from './uint32.ts'; 7 + import { Int64 } from './int64.ts'; 8 + import { Uint64 } from './uint64.ts'; 9 + import { Bool } from './bool.ts'; 10 + import { AtomicInt8 } from './atomic-int8.ts'; 11 + import { AtomicUint8 } from './atomic-uint8.ts'; 12 + import { AtomicInt16 } from './atomic-int16.ts'; 13 + import { AtomicUint16 } from './atomic-uint16.ts'; 14 + import { AtomicInt32 } from './atomic-int32.ts'; 15 + import { AtomicUint32 } from './atomic-uint32.ts'; 16 + import { AtomicInt64 } from './atomic-int64.ts'; 17 + import { AtomicUint64 } from './atomic-uint64.ts'; 18 + import { AtomicBool } from './atomic-bool.ts'; 19 + import { Mutex } from './mutex.ts'; 20 + import { RwLock } from './rwlock.ts'; 21 + 22 + export interface Descriptor<T> { 23 + (): T; 24 + byteSize: number; 25 + byteAlignment: number; 26 + _class: new (buffer: SharedArrayBuffer, byteOffset: number) => T; 27 + } 28 + 29 + function makeDescriptor<T>( 30 + factory: () => T, 31 + byteSize: number, 32 + byteAlignment: number, 33 + _class: new (buffer: SharedArrayBuffer, byteOffset: number) => T, 34 + ): Descriptor<T> { 35 + return Object.assign(factory, { byteSize, byteAlignment, _class }); 36 + } 37 + 38 + export const int8: Descriptor<Int8> = makeDescriptor(() => new Int8(), Int8.byteSize, Int8.byteAlignment, Int8); 39 + export const uint8: Descriptor<Uint8> = makeDescriptor(() => new Uint8(), Uint8.byteSize, Uint8.byteAlignment, Uint8); 40 + export const int16: Descriptor<Int16> = makeDescriptor(() => new Int16(), Int16.byteSize, Int16.byteAlignment, Int16); 41 + export const uint16: Descriptor<Uint16> = makeDescriptor(() => new Uint16(), Uint16.byteSize, Uint16.byteAlignment, Uint16); 42 + export const int32: Descriptor<Int32> = makeDescriptor(() => new Int32(), Int32.byteSize, Int32.byteAlignment, Int32); 43 + export const uint32: Descriptor<Uint32> = makeDescriptor(() => new Uint32(), Uint32.byteSize, Uint32.byteAlignment, Uint32); 44 + export const int64: Descriptor<Int64> = makeDescriptor(() => new Int64(), Int64.byteSize, Int64.byteAlignment, Int64); 45 + export const uint64: Descriptor<Uint64> = makeDescriptor(() => new Uint64(), Uint64.byteSize, Uint64.byteAlignment, Uint64); 46 + export const bool: Descriptor<Bool> = makeDescriptor(() => new Bool(), Bool.byteSize, Bool.byteAlignment, Bool); 47 + 48 + export const int8atomic: Descriptor<AtomicInt8> = makeDescriptor(() => new AtomicInt8(), AtomicInt8.byteSize, AtomicInt8.byteAlignment, AtomicInt8); 49 + export const uint8atomic: Descriptor<AtomicUint8> = makeDescriptor(() => new AtomicUint8(), AtomicUint8.byteSize, AtomicUint8.byteAlignment, AtomicUint8); 50 + export const int16atomic: Descriptor<AtomicInt16> = makeDescriptor(() => new AtomicInt16(), AtomicInt16.byteSize, AtomicInt16.byteAlignment, AtomicInt16); 51 + export const uint16atomic: Descriptor<AtomicUint16> = makeDescriptor(() => new AtomicUint16(), AtomicUint16.byteSize, AtomicUint16.byteAlignment, AtomicUint16); 52 + export const int32atomic: Descriptor<AtomicInt32> = makeDescriptor(() => new AtomicInt32(), AtomicInt32.byteSize, AtomicInt32.byteAlignment, AtomicInt32); 53 + export const uint32atomic: Descriptor<AtomicUint32> = makeDescriptor(() => new AtomicUint32(), AtomicUint32.byteSize, AtomicUint32.byteAlignment, AtomicUint32); 54 + export const int64atomic: Descriptor<AtomicInt64> = makeDescriptor(() => new AtomicInt64(), AtomicInt64.byteSize, AtomicInt64.byteAlignment, AtomicInt64); 55 + export const uint64atomic: Descriptor<AtomicUint64> = makeDescriptor(() => new AtomicUint64(), AtomicUint64.byteSize, AtomicUint64.byteAlignment, AtomicUint64); 56 + export const boolatomic: Descriptor<AtomicBool> = makeDescriptor(() => new AtomicBool(), AtomicBool.byteSize, AtomicBool.byteAlignment, AtomicBool); 57 + 58 + export const mutex: Descriptor<Mutex> = makeDescriptor(() => new Mutex(), Mutex.byteSize, Mutex.byteAlignment, Mutex); 59 + export const rwlock: Descriptor<RwLock> = makeDescriptor(() => new RwLock(), RwLock.byteSize, RwLock.byteAlignment, RwLock);
+6
src/shared/index.ts
··· 21 21 export { RwLock, ReadGuard, WriteGuard } from './rwlock.ts'; 22 22 export { slab } from './slab.ts'; 23 23 export { SharedStruct } from './shared-struct.ts'; 24 + export { 25 + int8, uint8, int16, uint16, int32, uint32, int64, uint64, bool, 26 + int8atomic, uint8atomic, int16atomic, uint16atomic, int32atomic, uint32atomic, int64atomic, uint64atomic, boolatomic, 27 + mutex, rwlock, 28 + } from './descriptors.ts'; 29 + export type { Descriptor } from './descriptors.ts';
+90
test/shared/descriptors.test.ts
··· 1 + import { describe, it } from 'node:test'; 2 + import assert from 'node:assert/strict'; 3 + import { 4 + int8, uint8, int16, uint16, int32, uint32, int64, uint64, bool, 5 + int8atomic, uint8atomic, int16atomic, uint16atomic, int32atomic, uint32atomic, int64atomic, uint64atomic, boolatomic, 6 + mutex, rwlock, 7 + } from 'moroutine'; 8 + 9 + describe('descriptors', () => { 10 + it('int32() creates a Loadable<number>', () => { 11 + const x = int32(); 12 + assert.equal(x.load(), 0); 13 + x.store(42); 14 + assert.equal(x.load(), 42); 15 + }); 16 + 17 + it('int64() creates a Loadable<bigint>', () => { 18 + const x = int64(); 19 + assert.equal(x.load(), 0n); 20 + x.store(99n); 21 + assert.equal(x.load(), 99n); 22 + }); 23 + 24 + it('bool() creates a Loadable<boolean>', () => { 25 + const x = bool(); 26 + assert.equal(x.load(), false); 27 + x.store(true); 28 + assert.equal(x.load(), true); 29 + }); 30 + 31 + it('int32atomic() creates an atomic with add/sub/etc', () => { 32 + const x = int32atomic(); 33 + x.store(10); 34 + assert.equal(x.add(5), 10); 35 + assert.equal(x.load(), 15); 36 + }); 37 + 38 + it('boolatomic() creates an atomic bool', () => { 39 + const x = boolatomic(); 40 + assert.equal(x.load(), false); 41 + x.store(true); 42 + assert.equal(x.load(), true); 43 + assert.equal(x.exchange(false), true); 44 + }); 45 + 46 + it('all non-atomic descriptors create loadable values', () => { 47 + assert.equal(int8().load(), 0); 48 + assert.equal(uint8().load(), 0); 49 + assert.equal(int16().load(), 0); 50 + assert.equal(uint16().load(), 0); 51 + assert.equal(int32().load(), 0); 52 + assert.equal(uint32().load(), 0); 53 + assert.equal(int64().load(), 0n); 54 + assert.equal(uint64().load(), 0n); 55 + assert.equal(bool().load(), false); 56 + }); 57 + 58 + it('all atomic descriptors create loadable values', () => { 59 + assert.equal(int8atomic().load(), 0); 60 + assert.equal(uint8atomic().load(), 0); 61 + assert.equal(int16atomic().load(), 0); 62 + assert.equal(uint16atomic().load(), 0); 63 + assert.equal(int32atomic().load(), 0); 64 + assert.equal(uint32atomic().load(), 0); 65 + assert.equal(int64atomic().load(), 0n); 66 + assert.equal(uint64atomic().load(), 0n); 67 + assert.equal(boolatomic().load(), false); 68 + }); 69 + 70 + it('mutex() creates a mutex', async () => { 71 + const m = mutex(); 72 + const guard = await m.lock(); 73 + guard[Symbol.dispose](); 74 + }); 75 + 76 + it('rwlock() creates a rwlock', async () => { 77 + const rw = rwlock(); 78 + const guard = await rw.readLock(); 79 + rw.readUnlock(); 80 + }); 81 + 82 + it('descriptors have schema metadata', () => { 83 + assert.equal(int32.byteSize, 4); 84 + assert.equal(int32.byteAlignment, 4); 85 + assert.equal(typeof int32._class, 'function'); 86 + assert.equal(bool.byteSize, 1); 87 + assert.equal(int64.byteSize, 8); 88 + assert.equal(mutex.byteSize, 4); 89 + }); 90 + });