Eric Bower
·
23 Feb 24
race.ts
1import type { Callable, Operation, Task } from "../deps.ts";
2import { action, call, resource, spawn } from "../deps.ts";
3
4interface OpMap<T = unknown> {
5 [key: string]: Callable<T>;
6}
7
8export function raceMap<T>(
9 opMap: OpMap,
10): Operation<
11 {
12 [K in keyof OpMap<T>]: OpMap[K] extends (...args: any[]) => any
13 ? ReturnType<OpMap[K]>
14 : OpMap[K];
15 }
16> {
17 return resource(function* Race(provide) {
18 const keys = Object.keys(opMap);
19 const taskMap: { [key: string]: Task<unknown> } = {};
20 const resultMap: { [key: keyof OpMap]: OpMap[keyof OpMap] } = {};
21
22 const winner = yield* action<Task<unknown>>(function* (resolve) {
23 for (let i = 0; i < keys.length; i += 1) {
24 const key = keys[i];
25 yield* spawn(function* () {
26 const task = yield* spawn(function* () {
27 yield* call(opMap[key] as any);
28 });
29 taskMap[key] = task;
30 (resultMap as any)[key] = yield* task;
31 resolve(task);
32 });
33 }
34 });
35
36 for (let i = 0; i < keys.length; i += 1) {
37 const key = keys[i];
38 const task = taskMap[key];
39 if (task === winner) {
40 continue;
41 }
42
43 yield* spawn(() => task.halt());
44 }
45
46 yield* provide(resultMap);
47 });
48}