import { Converter } from "./sync.js"; export interface Collector { initialize(): TAccumulator; accumulate(accumulator: TAccumulator, element: TElement): void; finalize(accumulator: TAccumulator): TResult; } class SimpleCollector implements Collector { readonly #initialize: () => TAccumulator; readonly #accumulate: (accumulator: TAccumulator, element: TElement) => void; readonly #finalize: (accumulator: TAccumulator) => TResult; constructor(initialize: () => TAccumulator, accumulate: (accumulator: TAccumulator, element: TElement) => void, finalize: (accumulator: TAccumulator) => TResult) { this.#initialize = initialize; this.#accumulate = accumulate; this.#finalize = finalize; } initialize() { return this.#initialize(); } accumulate(accumulator: TAccumulator, element: TElement) { this.#accumulate(accumulator, element); } finalize(accumulator: TAccumulator): TResult { return this.#finalize(accumulator); } } export function create(initialize: () => TAccumulator, accumulate: (accumulator: TAccumulator, element: TElement) => void, finalize: (accumulator: TAccumulator) => TResult): Collector { return new SimpleCollector(initialize, accumulate, finalize); } class ToArrayCollector implements Collector { initialize(): TElement[] { return []; } accumulate(accumulator: TElement[], element: TElement) { accumulator.push(element); } finalize(accumulator: TElement[]) { return accumulator; } } const toArrayCollector = new ToArrayCollector(); export function toArray(): Collector { return toArrayCollector; } class ToObjectCollector implements Collector, Record> { readonly #keySelector: Converter; readonly #valueSelector: Converter; constructor(keySelector: Converter, valueSelector: Converter) { this.#keySelector = keySelector; this.#valueSelector = valueSelector; } initialize() { return {} as Record; } accumulate(accumulator: Record, element: TElement) { const key = this.#keySelector(element); const value = this.#valueSelector(element); accumulator[key] = value; } finalize(accumulator: Record) { return accumulator; } } export function toObject(keySelector: Converter, valueSelector: Converter): Collector> { return new ToObjectCollector(keySelector, valueSelector); } class ToMapCollector implements Collector, Map> { readonly #keySelector: Converter; readonly #valueSelector: Converter; constructor(keySelector: Converter, valueSelector: Converter) { this.#keySelector = keySelector; this.#valueSelector = valueSelector; } initialize() { return new Map(); } accumulate(accumulator: Map, element: TElement) { const key = this.#keySelector(element); const value = this.#valueSelector(element); accumulator.set(key, value); } finalize(accumulator: Map) { return accumulator; } } export function toMap(keySelector: Converter, valueSelector: Converter): Collector> { return new ToMapCollector(keySelector, valueSelector); } class ToSetCollector implements Collector, Set> { initialize() { return new Set(); } accumulate(accumulator: Set, element: TElement) { accumulator.add(element); } finalize(accumulator: Set) { return accumulator; } } const toSetCollector = new ToSetCollector(); export function toSet(): Collector> { return toSetCollector; } class JoinCollector implements Collector { readonly #delimiter: string; readonly #prefix: string; readonly #suffix: string; constructor(delimiter?: string, prefix?: string, suffix?: string) { this.#delimiter = delimiter ?? ""; this.#prefix = prefix ?? ""; this.#suffix = suffix ?? ""; } initialize(): any[] { return []; } accumulate(accumulator: any[], element: string) { accumulator.push(element); } finalize(accumulator: any[]) { return this.#prefix + accumulator.join(this.#delimiter) + this.#suffix; } } export function join(delimiter?: string, prefix?: string, suffix?: string): Collector { return new JoinCollector(delimiter, prefix, suffix); } class SumCollector implements Collector { initialize() { return { sum: 0 }; } accumulate(accumulator: { sum: number }, element: number) { accumulator.sum += element; } finalize(accumulator: { sum: number }) { return accumulator.sum; } } const sumCollector = new SumCollector(); export function sum(): Collector { return sumCollector; } class BigIntSumCollector implements Collector { initialize() { return { sum: 0n, }; } accumulate(accumulator: { sum: bigint }, element: bigint) { accumulator.sum += element; } finalize(accumulator: { sum: bigint }) { return accumulator.sum; } } const bigintSumCollector = new BigIntSumCollector(); export function bigintSum(): Collector { return bigintSumCollector; } class AverageCollector implements Collector { initialize() { return { count: 0, sum: 0 }; } accumulate(accumulator: { count: number, sum: number }, element: number) { accumulator.count++; accumulator.sum += element; } finalize(accumulator: { count: number, sum: number }) { return accumulator.count === 0 ? 0 : accumulator.sum / accumulator.count; } } const averageCollector = new AverageCollector(); export function average(): Collector { return averageCollector; } class BigIntAverageCollector implements Collector { initialize() { return { count: 0, sum: 0n }; } accumulate(accumulator: { count: number, sum: bigint }, element: bigint) { accumulator.count++; accumulator.sum += element; } finalize(accumulator: { count: number, sum: bigint }) { return accumulator.count === 0 ? 0n : accumulator.sum / BigInt(accumulator.count); } } const bigintAverageCollector = new BigIntAverageCollector(); export function bigintAverage(): Collector { return bigintAverageCollector; }