spica
Version:
Supervisor, Coroutine, Channel, select, AtomicPromise, Cancellation, Cache, List, Queue, Stack, and some utils.
47 lines (45 loc) • 1.45 kB
text/typescript
import { isArray } from './alias';
import { Coroutine, CoroutineOptions } from './coroutine';
import { AtomicPromise, never } from './promise';
import { select } from './select';
export class Coaggregator<T = unknown, R = T, S = unknown> extends Coroutine<T, R, S> {
constructor(
coroutines: Iterable<Coroutine<T, R, S>>,
reducer: (results: T[]) => T = results => results[0],
opts?: CoroutineOptions,
) {
super(async function* () {
const cs = isArray(coroutines)
? coroutines
: [...coroutines];
this.then(
result => {
for (const co of cs) {
co[Coroutine.exit](result);
}
},
reason => {
const rejection = AtomicPromise.reject(reason);
for (const co of cs) {
co[Coroutine.exit](rejection);
}
});
const results: T[] = [];
for await (const { name, result } of select(cs)) {
assert(Number.isSafeInteger(+name));
if (result.done) {
results[name] = result.value;
}
else {
yield result.value;
}
}
assert(Object.keys(results).length === results.length);
assert(results.length === cs.length);
results.length === 0
? this[Coroutine.terminate](new Error(`Spica: Coaggregator: No result`))
: this[Coroutine.exit](reducer(results));
return never;
}, { delay: false, ...opts });
}
}