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.

at main 58 lines 1.8 kB view raw
1import type { Transferable } from 'node:worker_threads'; 2import { MessagePort } from 'node:worker_threads'; 3 4const TRANSFER = Symbol.for('moroutine.transfer'); 5 6export interface Transferred<T> { 7 readonly [TRANSFER]: true; 8 readonly value: T; 9} 10 11/** 12 * Marks a value for zero-copy transfer via postMessage. The original becomes detached after sending. 13 * @param value - The value to transfer (ArrayBuffer, TypedArray, MessagePort, or stream). 14 * @returns The same value, typed unchanged for transparent use as a moroutine argument. 15 */ 16export function transfer<T>(value: T): T { 17 return { [TRANSFER]: true as const, value } as unknown as T; 18} 19 20export function extractTransferables(args: unknown[]): { args: unknown[]; transfer: Transferable[] } { 21 const transferList: Transferable[] = []; 22 const processedArgs = args.map((arg) => { 23 if (typeof arg === 'object' && arg !== null && TRANSFER in arg) { 24 const value = (arg as Transferred<unknown>).value; 25 collectTransferables(value, transferList); 26 return value; 27 } 28 return arg; 29 }); 30 return { args: processedArgs, transfer: transferList }; 31} 32 33export function collectTransferables(value: unknown, list: Transferable[]): void { 34 if (!(typeof value === 'object' && value !== null)) return; 35 36 // Directly transferable 37 if ( 38 value instanceof ArrayBuffer || 39 value instanceof MessagePort || 40 value instanceof ReadableStream || 41 value instanceof WritableStream 42 ) { 43 list.push(value); 44 return; 45 } 46 47 // TypedArray or DataView — extract .buffer 48 if (ArrayBuffer.isView(value) && value.buffer instanceof ArrayBuffer) { 49 list.push(value.buffer); 50 return; 51 } 52 53 // TransformStream — extract both streams 54 if (value instanceof TransformStream) { 55 list.push(value.readable, value.writable); 56 return; 57 } 58}