import { assert } from "../../diagnostics"; import { tryGetCountDirect } from "./count"; import { asLinq, LinqWrapper } from "../linqWrapper"; import { IntermediateLinqWrapper } from "../internal"; import { BuiltInLinqTraits, TryGetCountDirectSymbol } from "../traits"; import { PipeBody, PipeFunction } from "../../pipables"; /* eslint-disable @typescript-eslint/no-explicit-any */ export type ZippedSequenceElementSelector = (...elements: Ts) => TResult; /** * Infrastructure. Do not use this member in your own code. */ export type TypeArrayToIterableArray = { [i in keyof Ts]: Iterable }; export function zip(sequence2: Iterable): PipeBody, LinqWrapper<[T, T2]>>; export function zip(sequence2: Iterable, selector?: ZippedSequenceElementSelector<[T, T2], TResult>): PipeBody, LinqWrapper>; export function zip(sequence2: Iterable, sequence3: Iterable): PipeBody, LinqWrapper<[T, T2, T3]>>; export function zip(sequence2: Iterable, sequence3: Iterable, selector?: ZippedSequenceElementSelector<[T, T2, T3], TResult>): PipeBody, LinqWrapper>; export function zip(...sequences: TypeArrayToIterableArray): PipeBody, LinqWrapper<[T, ...Ts]>>; export function zip(...args: [...TypeArrayToIterableArray, selector?: ZippedSequenceElementSelector<[T, ...Ts], TResult>]): PipeBody, LinqWrapper>; export function zip( ...args: [...TypeArrayToIterableArray, selector?: ZippedSequenceElementSelector<[T, ...Ts], TResult>] ): PipeBody, LinqWrapper> { /* eslint-enable @typescript-eslint/no-explicit-any */ return target => { let iterables: TypeArrayToIterableArray<[T, ...Ts]>; let selector: ZippedSequenceElementSelector<[T, ...Ts], TResult> | undefined; if (typeof args.at(-1) === "function" || args.at(-1) == null) { iterables = [target.unwrap(), ...args.slice(0, -1)] as typeof iterables; selector = args[args.length - 1] as typeof selector ?? undefined; } else { iterables = [target.unwrap(), ...args] as typeof iterables; selector = undefined; } return new ZipLinqWrapper<[T, ...Ts], TResult>({ iterables, selector, }); }; } zip satisfies PipeFunction; // eslint-disable-next-line @typescript-eslint/no-explicit-any interface ZipIteratorState { readonly iterables: Array>; selector?: ZippedSequenceElementSelector; } // eslint-disable-next-line @typescript-eslint/no-explicit-any class ZipLinqWrapper extends IntermediateLinqWrapper> implements BuiltInLinqTraits { public override *[Symbol.iterator](): Iterator { const { iterables, selector } = this.__state; const iterators = iterables.map(it => it[Symbol.iterator]()); while (true) { const currentItem = [] as unknown as Ts; for (const it of iterators) { const next = it.next(); if (next.done) return; currentItem.push(next.value); } if (selector) yield selector(...currentItem); else yield currentItem as unknown as TResult; } } public [TryGetCountDirectSymbol](): number | undefined { const { iterables } = this.__state; assert(iterables.length > 0); let cur = asLinq(iterables[0]).$(tryGetCountDirect()); if (cur == null) return undefined; for (let i = 1; i < iterables.length; i++) { const count = asLinq(iterables[i]).$(tryGetCountDirect()); if (count == null) return undefined; if (cur > count) cur = count; } return cur; } }