| 444 | { -readonly [K in keyof O]: O[K] extends Effected<Effect, infer R> ? R : never } |
| 445 | >; |
| 446 | static all( |
| 447 | effects: Iterable<Effected<Effect, unknown>> | Record<string, Effected<Effect, unknown>>, |
| 448 | ): Effected<Effect, unknown> { |
| 449 | return effected(() => { |
| 450 | const isIterable = Symbol.iterator in effects; |
| 451 | const keys: (string | number)[] = []; |
| 452 | const iterators: Iterator<Effect, unknown, unknown>[] = []; |
| 453 | if (isIterable) { |
| 454 | for (const e of effects) iterators.push(e[Symbol.iterator]()); |
| 455 | Array.prototype.push.apply( |
| 456 | keys, |
| 457 | Array.from({ length: iterators.length }, (_, i) => i), |
| 458 | ); |
| 459 | } else { |
| 460 | for (const key in effects) { |
| 461 | if (!Object.prototype.hasOwnProperty.call(effects, key)) continue; |
| 462 | keys.push(key); |
| 463 | iterators.push(effects[key]![Symbol.iterator]()); |
| 464 | } |
| 465 | } |
| 466 | |
| 467 | if (keys.length === 0) return { next: () => ({ done: true, value: isIterable ? [] : {} }) }; |
| 468 | |
| 469 | const label = Symbol(); |
| 470 | |
| 471 | const results: any = isIterable ? new Array(keys.length) : {}; |
| 472 | const states = Array.from( |
| 473 | { length: keys.length }, |
| 474 | () => "idle" as "idle" | "pending" | "done", |
| 475 | ); |
| 476 | let recover: ((payload: { _effectRecover: symbol; index: number }) => void) | null = null; |
| 477 | |
| 478 | let index = 0; |
| 479 | const nextIdleIndex = () => { |
| 480 | let i = index; |
| 481 | do i = (i + 1) % keys.length; |
| 482 | while (states[i] !== "idle" && i !== index); |
| 483 | return i === index ? null : i; |
| 484 | }; |
| 485 | |
| 486 | return { |
| 487 | next: (...args: [] | [unknown]) => { |
| 488 | if (states.every((s) => s === "done")) return { done: true, value: results }; |
| 489 | |
| 490 | if (args[0] != null && (args[0] as any)._effectInterrupt === label) { |
| 491 | const currIndex = index; |
| 492 | states[currIndex] = "pending"; |
| 493 | void ((args[0] as any).with as Promise<unknown>).then((value) => { |
| 494 | results[keys[currIndex]!] = value; |
| 495 | states[currIndex] = "idle"; |
| 496 | recover!({ _effectRecover: label, index: currIndex }); |
| 497 | }); |
| 498 | const nextIndex = nextIdleIndex(); |
| 499 | |
| 500 | if (!nextIndex) |
| 501 | return { |
| 502 | done: false, |
| 503 | value: { |