import { registry, isModuleFrozen } from './registry.ts'; import { PromiseLikeTask } from './task.ts'; import { AsyncIterableTask } from './stream-task.ts'; import type { Task } from './runner.ts'; const counters = new Map(); /** * Wraps a function to run on a worker thread. Must be called at module scope. * @param importMeta - The `import.meta` of the calling module, used to identify the source file. * @param fn - The function to offload to a worker thread. * @returns A callable that creates a {@link Task} when invoked. */ /** A value or a Task that resolves to that value on the worker. */ export type Arg = T | Task; type TaskableArgs = { [K in keyof A]: Arg }; type Moroutine = { (...args: A): Task, A> & PromiseLike>; (...args: TaskableArgs): Task, A> & PromiseLike>; /** Stable id tying tasks back to this moroutine. Used by {@link isTask}. */ readonly id: string; }; type AsyncIterableMoroutine = { (...args: A): Task, A> & AsyncIterable; (...args: TaskableArgs): Task, A> & AsyncIterable; /** Stable id tying tasks back to this moroutine. Used by {@link isTask}. */ readonly id: string; }; type IsNever = [T] extends [never] ? true : false; type MoReturn = IsNever extends true ? Moroutine : [R] extends [AsyncGenerator] ? AsyncIterableMoroutine : Moroutine; function isAsyncGeneratorFunction(fn: Function): boolean { return fn.constructor.name === 'AsyncGeneratorFunction'; } export function mo(importMeta: ImportMeta, fn: (...args: A) => R): MoReturn { const url = importMeta.url; if (isModuleFrozen(url)) { throw new Error( `Cannot call mo() for ${url} after a task from this module has been dispatched. ` + 'All mo() calls must happen at module load time.', ); } const index = counters.get(url) ?? 0; counters.set(url, index + 1); const id = `${url}#${index}`; registry.set(id, fn); const factory = isAsyncGeneratorFunction(fn) ? (...args: unknown[]) => new AsyncIterableTask(id, args) : (...args: unknown[]) => new PromiseLikeTask(id, args); Object.defineProperty(factory, 'id', { value: id, enumerable: true }); return factory as unknown as MoReturn; }