import { PipeBody, PipeFunction } from "../../pipables"; import type { LinqWrapper } from "../linqWrapper"; import { IntermediateLinqWrapper } from "../internal"; import { IndexedSequenceElementPredicate, SequenceElementTypeAssertionPredicate } from "./typing"; export function where(predicate: SequenceElementTypeAssertionPredicate): PipeBody,LinqWrapper>; export function where(predicate: IndexedSequenceElementPredicate): PipeBody,LinqWrapper>; export function where(predicate: IndexedSequenceElementPredicate): PipeBody,LinqWrapper> { // n.b. Even if `this` is empty upon the time of invocation of this function, // `this` may have items when iterator gets enumerated later. return target => { if (target instanceof WhereLinqWrapper) { const state = target.__state; return new WhereLinqWrapper({ ...state, predicates: [...state.predicates, predicate], }); } return new WhereLinqWrapper({ iterable: target.unwrap(), predicates: [predicate], }); }; } where satisfies PipeFunction; interface WhereIteratorInfo { readonly iterable: Iterable; predicates: ReadonlyArray>; } class WhereLinqWrapper extends IntermediateLinqWrapper> { public override *[Symbol.iterator](): Iterator { const { iterable, predicates } = this.__state; const indices = new Array(predicates.length).fill(0); ELEMENT: for (const e of iterable) { for (let j = 0; j < predicates.length; j++) { const passed = predicates[j](e, indices[j]); indices[j]++; if (!passed) continue ELEMENT; } // Passed all predicates yield e; } } }