UNPKG

ix

Version:

The Interactive Extensions for JavaScript

195 lines (176 loc) 8.91 kB
import { AsyncIterableX } from '../asynciterablex.js'; import { OperatorAsyncFunction } from '../../interfaces.js'; import { wrapWithAbort } from './withabort.js'; import { throwIfAborted } from '../../aborterror.js'; import { identity } from '../../util/identity.js'; import { safeRace } from '../../util/safeRace.js'; // eslint-disable-next-line @typescript-eslint/no-empty-function const NEVER_PROMISE = new Promise(() => {}); type MergeResult<T> = { value: T; index: number }; function wrapPromiseWithIndex<T>(promise: Promise<T>, index: number) { return promise.then((value) => ({ value, index })) as Promise<MergeResult<T>>; } /** @ignore */ export class WithLatestFromAsyncIterable<TSource> extends AsyncIterableX<TSource[]> { private _source: AsyncIterable<TSource>; private _others: AsyncIterable<TSource>[]; constructor(source: AsyncIterable<TSource>, others: AsyncIterable<TSource>[]) { super(); this._source = source; this._others = others; } async *[Symbol.asyncIterator](signal?: AbortSignal) { throwIfAborted(signal); const length = this._others.length; const newLength = length + 1; const iterators = new Array<AsyncIterator<TSource>>(newLength); const nexts = new Array<Promise<MergeResult<IteratorResult<TSource>>>>(newLength); let hasValueAll = false; const hasValue = new Array(length); const values = new Array(length); hasValue.fill(false); for (let i = 0; i < length; i++) { const iterator = wrapWithAbort(this._others[i], signal)[Symbol.asyncIterator](); iterators[i] = iterator; nexts[i] = wrapPromiseWithIndex(iterator.next(), i); } const it = wrapWithAbort(this._source, signal)[Symbol.asyncIterator](); iterators[length] = it; nexts[length] = wrapPromiseWithIndex(it.next(), length); for (;;) { const next = safeRace(nexts); const { value: { value: value$, done: done$ }, index, } = await next; if (index === length) { if (done$) { break; } const iterator$ = iterators[index]; nexts[index] = wrapPromiseWithIndex(iterator$.next(), index); if (hasValueAll) { yield [value$, ...values]; } } else if (done$) { nexts[index] = <Promise<MergeResult<IteratorResult<TSource>>>>NEVER_PROMISE; } else { values[index] = value$; hasValue[index] = true; hasValueAll = hasValue.every(identity); const iterator$ = iterators[index]; nexts[index] = wrapPromiseWithIndex(iterator$.next(), index); } } } } /** * Merges multiple async-iterable sequences into one async-iterable sequence by combining each element * from the first source with the latest element from the other sources, if any. * * @template T The type of the elements in the first source sequence. * @template T2 The type of the elements in the second source sequence. * @param {AsyncIterable<T2>} source2 Second async-iterable source. * @returns {OperatorAsyncFunction<T, [T, T2]>} An async-iterable sequence containing the result of combining * each element of the first source with the latest element from the second source, if any as an array. */ export function withLatestFrom<T, T2>( source2: AsyncIterable<T2> ): OperatorAsyncFunction<T, [T, T2]>; /** * Merges multiple async-iterable sequences into one async-iterable sequence by combining each element * from the first source with the latest element from the other sources, if any. * * @template T The type of the elements in the first source sequence. * @template T2 The type of the elements in the second source sequence. * @template T3 The type of the elements in the third source sequence. * @param {AsyncIterable<T2>} source2 Second async-iterable source. * @param {AsyncIterable<T3>} source3 Third async-iterable source. * @returns {OperatorAsyncFunction<T, [T, T2, T3]>} An async-iterable sequence containing the result of combining * each element of the first source with the latest element from the second source, if any as an array. */ export function withLatestFrom<T, T2, T3>( source2: AsyncIterable<T2>, source3: AsyncIterable<T3> ): OperatorAsyncFunction<T, [T, T2, T3]>; /** * Merges multiple async-iterable sequences into one async-iterable sequence by combining each element * from the first source with the latest element from the other sources, if any. * * @template T The type of the elements in the first source sequence. * @template T2 The type of the elements in the second source sequence. * @template T3 The type of the elements in the third source sequence. * @template T4 The type of the elements in the fourth source sequence. * @param {AsyncIterable<T2>} source2 Second async-iterable source. * @param {AsyncIterable<T3>} source3 Third async-iterable source. * @param {AsyncIterable<T4>} source4 Fourth async-iterable source. * @returns {OperatorAsyncFunction<T, [T, T2, T3, T4]>} An async-iterable sequence containing the result of combining * each element of the first source with the latest element from the second source, if any as an array. */ export function withLatestFrom<T, T2, T3, T4>( source2: AsyncIterable<T2>, source3: AsyncIterable<T3>, source4: AsyncIterable<T4> ): OperatorAsyncFunction<T, [T, T2, T3, T4]>; /** * Merges multiple async-iterable sequences into one async-iterable sequence by combining each element * from the first source with the latest element from the other sources, if any. * * @template T The type of the elements in the first source sequence. * @template T2 The type of the elements in the second source sequence. * @template T3 The type of the elements in the third source sequence. * @template T4 The type of the elements in the fourth source sequence. * @template T5 The type of the elements in the fifth source sequence. * @param {AsyncIterable<T2>} source2 Second async-iterable source. * @param {AsyncIterable<T3>} source3 Third async-iterable source. * @param {AsyncIterable<T4>} source4 Fourth async-iterable source. * @param {AsyncIterable<T5>} source5 Fifth async-iterable source. * @returns {OperatorAsyncFunction<T, [T, T2, T3, T4, T5]>} An async-iterable sequence containing the result of combining * each element of the first source with the latest element from the second source, if any as an array. */ export function withLatestFrom<T, T2, T3, T4, T5>( source2: AsyncIterable<T2>, source3: AsyncIterable<T3>, source4: AsyncIterable<T4>, source5: AsyncIterable<T5> ): OperatorAsyncFunction<T, [T, T2, T3, T4, T5]>; /** * Merges multiple async-iterable sequences into one async-iterable sequence by combining each element * from the first source with the latest element from the other sources, if any. * * @template T The type of the elements in the first source sequence. * @template T2 The type of the elements in the second source sequence. * @template T3 The type of the elements in the third source sequence. * @template T4 The type of the elements in the fourth source sequence. * @template T5 The type of the elements in the fifth source sequence. * @template T6 The type of the elements in the sixth source sequence. * @param {AsyncIterable<T2>} source2 Second async-iterable source. * @param {AsyncIterable<T3>} source3 Third async-iterable source. * @param {AsyncIterable<T4>} source4 Fourth async-iterable source. * @param {AsyncIterable<T5>} source5 Fifth async-iterable source. * @param {AsyncIterable<T6>} source6 Sixth async-iterable source. * @returns {OperatorAsyncFunction<T, [T, T2, T3, T4, T5, T6]>} An async-iterable sequence containing the result of combining * each element of the first source with the latest element from the second source, if any as an array. */ export function withLatestFrom<T, T2, T3, T4, T5, T6>( source2: AsyncIterable<T2>, source3: AsyncIterable<T3>, source4: AsyncIterable<T4>, source5: AsyncIterable<T5>, source6: AsyncIterable<T6> ): OperatorAsyncFunction<T, [T, T2, T3, T4, T5, T6]>; /** * Merges multiple async-iterable sequences into one async-iterable sequence by combining each element * from the first source with the latest element from the other sources, if any. * * @template T The type of the elements in the source sequences. * @param {...AsyncIterable<T>[]} sources The source sequences. * @returns {OperatorAsyncFunction<T, T[]>} An async-iterable sequence containing the result of combining * each element of the first source with the latest element from the second source, if any as an array. */ export function withLatestFrom<T>(...sources: AsyncIterable<T>[]): OperatorAsyncFunction<T, T[]>; export function withLatestFrom<T>(...sources: any[]): OperatorAsyncFunction<T, T[]> { return function withLatestFromOperatorFunction(source: AsyncIterable<T>) { return new WithLatestFromAsyncIterable<T>(source, sources); }; }