import { CollectFun, Eq, ErrBase, OptLazy } from '@rimbu/common';
import { type StreamSource } from '@rimbu/stream';
/**
 * A `Reducer` is a stand-alone calculation that takes input values of type I, and, when requested, produces an output value of type O.
 * @typeparam I - the input value type
 * @typeparam O - the output value type
 */
export type Reducer<I, O = I> = Reducer.Impl<I, O, unknown>;
export declare namespace Reducer {
    /**
     * The Implementation interface for a `Reducer`, which also exposes the internal state type.
     * @typeparam I - the input value type
     * @typeparam O - the output value type
     * @typeparam S - the internal state type
     */
    interface Impl<I, O, S = unknown> {
        /**
         * A function that produces the initial state value for the reducer algorithm.
         * @param initHalt - a callback function that, if called, indicates that the reducer does not accept any input.
         */
        readonly init: (initHalt: () => void) => S;
        /**
         * Returns the next state based on the given input values:
         * @param state - the current state
         * @param elem - the current input value
         * @param index - the current input index
         * @param halt - a function that, when called, ensures no more values are passed to the reducer
         */
        next(state: S, elem: I, index: number, halt: () => void): S;
        /**
         * Returns the output value based on the given `state`.
         * @param state - the current state
         * @param index - the value index
         * @param halted - a boolean indicating whether the reducer is halted
         */
        stateToResult(state: S, index: number, halted: boolean): O;
        /**
         * Returns a `Reducer` instance that only passes values to the reducer that satisy the given `pred` predicate.
         * @param pred - a function that returns true if the value should be passed to the reducer based on the following inputs:<br/>
         * - value: the current input value<br/>
         * - index: the current input index<br/>
         * - halt: function that, when called, ensures no more new values are passed to the reducer
         * @param options - (optional) an object containing the following properties:<br/>
         * - negate: (default: false) when true will invert the given predicate
         * @note if the predicate is a type guard, the return type is automatically inferred
         * @example
         * ```ts
         * Reducer.sum.filterInput(v => v > 10)
         * // this reducer will only sum values larger than 10
         * ```
         */
        filterInput<IF extends I>(pred: (value: I, index: number, halt: () => void) => value is IF, options?: {
            negate?: false | undefined;
        }): Reducer<IF, O>;
        filterInput<IF extends I>(pred: (value: I, index: number, halt: () => void) => value is IF, options: {
            negate: true;
        }): Reducer<Exclude<I, IF>, O>;
        filterInput(pred: (value: I, index: number, halt: () => void) => boolean, options?: {
            negate?: boolean | undefined;
        }): Reducer<I, O>;
        /**
         * Returns a `Reducer` instance that converts its input values using given `mapFun` before passing them to this reducer.
         * @param mapFun - a function that returns a new value to pass to the reducer based on the following inputs:<br/>
         * - value: the current input value<br/>
         * - index: the current input index
         * @typeparam I2 - the resulting reducer input type
         * @example
         * ```ts
         * Reducer.sum.mapInput(v => v * 2)
         * // this reducer will double all input values before summing them
         * ```
         */
        mapInput: <I2>(mapFun: (value: I2, index: number) => I) => Reducer<I2, O>;
        /**
         * Returns a `Reducer` instance that converts each output value from some source reducer into an arbitrary number of output values
         * using given `flatMapFun` before passing them to this reducer.
         * @typeparam I2 - the resulting reducer input type
         * @param mapFun - a function that returns a new value to pass to the reducer based on the following inputs:<br/>
         * - value: the current input value<br/>
         * - index: the current input index
         * @example
         * ```ts
         * Reducer.sum.flatMapInput(v => [v, v + 1])
         * // this reducer will add v and v + 1 to the sum for each input value
         * ```
         */
        flatMapInput<I2>(flatMapFun: (value: I2, index: number) => StreamSource<I>): Reducer<I2, O>;
        /**
         * Returns a `Reducer` instance that converts or filters its input values using given `collectFun` before passing them to the reducer.
         * @param collectFun - a function receiving<br/>
         * - `value`: the next value<br/>
         * - `index`: the value index<br/>
         * - `skip`: a token that, when returned, will not add a value to the resulting collection<br/>
         * - `halt`: a function that, when called, ensures no next elements are passed
         * @typeparam I2 - the resulting reducer input type
         * @example
         * ```ts
         * Reducer.sum.collectInput((v, _, skip) => v <= 10 ? skip : v * 2)
         * // this reducer will double all input values larger thant 10 before summing them,
         * // and will skip all values smaller than 10
         * ```
         */
        collectInput<I2>(collectFun: CollectFun<I2, I>): Reducer<I2, O>;
        /**
         * Returns a `Reducer` instance that converts its output values using given `mapFun`.
         * @typeparam O2 - the resulting reducer output type
         * @param mapFun - a function that takes the current output value and converts it to a new output value
         * @typeparam O2 - the new output type
         * @example
         * ```ts
         * Reducer.sum.mapOutput(String)
         * // this reducer will convert all its results to string before returning them
         * ```
         */
        mapOutput<O2>(mapFun: (value: O, index: number, halted: boolean) => O2): Reducer<I, O2>;
        /**
         * Returns a `Reducer` instance that takes at most the given `amount` of input elements, and will ignore subsequent elements.
         * @param amount - the amount of elements to accept
         * @example
         * ```ts
         * Stream.range({ end: 10 }).reduce(Reducer.sum.takeInput(2))
         * // => 1
         * ```
         */
        takeInput(amount: number): Reducer<I, O>;
        /**
         * Returns a `Reducer` instance that skips the first given `amount` of input elements, and will process subsequent elements.
         * @param amount - the amount of elements to skip
         * @example
         * ```ts
         * Stream.range({ end: 10 }).reduce(Reducer.sum.dropInput(9))
         * // => 19
         * ```
         */
        dropInput(amount: number): Reducer<I, O>;
        /**
         * Returns a `Reducer` instance that takes given `amount` of elements starting at given `from` index, and ignores other elements.
         * @param from - (default: 0) the index at which to start processing elements
         * @param amount - (optional) the amount of elements to process, if not given, processes all elements from the `from` index
         * @example
         * ```ts
         * Stream.range({ end: 10 }).reduce(Reducer.sum.sliceInput(1, 2))
         * // => 3
         * ```
         */
        sliceInput(from?: number, amount?: number): Reducer<I, O>;
        /**
         * Returns an 'AsyncReducer` instance that produces at most `amount` values.
         * @param amount - the maximum amount of values to produce.
         */
        takeOutput(amount: number): Reducer<I, O>;
        /**
         * Returns a 'Reducer` instance that produces until the given `pred` predicate returns true for
         * the output value.
         * @param pred - a function that returns true if the value should be passed to the reducer based on the following inputs:<br/>
         * - value: the current input value<br/>
         * - index: the current input index<br/>
         * - halt: function that, when called, ensures no more new values are passed to the reducer
         * @param options - (optional) an object containing the following properties:<br/>
         * - negate: (default: false) when true will invert the given predicate
         */
        takeOutputUntil(pred: (value: O, index: number) => boolean, options?: {
            negate?: boolean;
        }): Reducer<I, O>;
        /**
         * Returns a reducer that applies this reducer and then the `nextReducers` sequentially on halting of each reducer.
         * It provides the last output value of the active reducer.
         * @param nextReducers - an number of reducers consuming and producing the same types as the current reducer.
         * @example
         * ```ts
         * const result = Stream.range({ amount: 6 })
         *  .reduce(
         *    Reducer.sum
         *      .takeInput(3)
         *      .chain(
         *        [v => v > 10 ? Reducer.product : Reducer.sum]
         *      )
         *    )
         * console.log(result)
         * // => 21
         * ```
         */
        chain<O2 extends O>(nextReducers: StreamSource<OptLazy<Reducer<I, O2>, [O2]>>): Reducer<I, O2>;
        /**
         * Returns a 'runnable' instance of the current reducer specification. This instance maintains its own state
         * and indices, so that the instance only needs to be provided the input values, and output values can be
         * retrieved when needed. The state is kept private.
         * @example
         * ```ts
         * const reducer = Reducer.sum.mapOutput(v => v * 2);
         * const instance = reducer.compile();
         * instance.next(3);
         * instance.next(5);
         * console.log(instance.getOutput());
         * // => 16
         * ```
         */
        compile(): Reducer.Instance<I, O>;
    }
    /**
     * A base class that can be used to easily create `Reducer` instances.
     * @typeparam I - the input value type
     * @typeparam O - the output value type
     * @typeparam S - the internal state type
     */
    class Base<I, O, S> implements Reducer.Impl<I, O, S> {
        readonly init: (initHalt: () => void) => S;
        readonly next: (state: S, elem: I, index: number, halt: () => void) => S;
        readonly stateToResult: (state: S, index: number, halted: boolean) => O;
        constructor(init: (initHalt: () => void) => S, next: (state: S, elem: I, index: number, halt: () => void) => S, stateToResult: (state: S, index: number, halted: boolean) => O);
        filterInput(pred: (value: I, index: number, halt: () => void) => boolean, options?: {
            negate?: boolean | undefined;
        }): any;
        mapInput<I2>(mapFun: (value: I2, index: number) => I): Reducer<I2, O>;
        flatMapInput<I2>(flatMapFun: (value: I2, index: number) => StreamSource<I>): Reducer<I2, O>;
        collectInput<I2>(collectFun: CollectFun<I2, I>): Reducer<I2, O>;
        mapOutput<O2>(mapFun: (value: O, index: number, halted: boolean) => O2): Reducer<I, O2>;
        takeOutput(amount: number): Reducer<I, O>;
        takeOutputUntil(pred: (value: O, index: number) => boolean, options?: {
            negate?: boolean;
        }): Reducer<I, O>;
        takeInput(amount: number): Reducer<I, O>;
        dropInput(amount: number): Reducer<I, O>;
        sliceInput(from?: number, amount?: number): Reducer<I, O>;
        chain<O2 extends O>(nextReducers: StreamSource<OptLazy<Reducer<I, O2>, [O2]>>): Reducer<I, O2>;
        compile(): Reducer.Instance<I, O>;
    }
    /**
     * A reducer instance that manages its own state based on the reducer definition that
     * was used to create this instance.
     * @typeparam I - the input element type
     * @typeparam O - the output element type
     */
    interface Instance<I, O> {
        /**
         * Returns true if the reducer instance does not receive any more values, false otherwise.
         */
        get halted(): boolean;
        /**
         * Returns the index of the last received value.
         */
        get index(): number;
        /**
         * Method that, when called, halts the reducer instance so that it will no longer receive values.
         */
        halt(): void;
        /**
         * Sends a new value into the reducer instance.
         * @param value - the next input value
         */
        next(value: I): void;
        /**
         * Returns the output value based on the current given input values.
         */
        getOutput(): O;
    }
    /**
     * The default `Reducer.Impl` implementation.
     * @typeparam I - the input element type
     * @typeparam O - the output element type
     * @typeparam S - the reducer state type
     */
    class InstanceImpl<I, O, S> implements Reducer.Instance<I, O> {
        readonly reducer: Reducer.Impl<I, O, S>;
        constructor(reducer: Reducer.Impl<I, O, S>);
        ___state: S;
        ___index: number;
        ___halted: boolean;
        halt: () => void;
        get halted(): boolean;
        get index(): number;
        next: (value: I) => void;
        getOutput(): O;
    }
    /**
     * Returns a `Reducer` with the given options:
     * @param init - the initial state value
     * @param next - returns the next state value based on the given inputs:<br/>
     * - current: the current state<br/>
     * - next: the current input value<br/>
     * - index: the input index value<br/>
     * - halt: function that, when called, ensures no more elements are passed to the reducer
     * @param stateToResult - a function that converts the current state to an output value
     * @typeparam I - the input value type
     * @typeparam O - the output value type
     * @typeparam S - the internal state type
     * @example
     * ```ts
     * const evenNumberOfOnes = Reducer.create(
     *   true,
     *   (current, value: number) => (value === 1 ? !current : current),
     *   (state) => (state ? 'even' : 'not even')
     * );
     * const result = Stream.of(1, 2, 3, 2, 1).reduce(evenNumberOfOnes);
     * console.log(result);
     * // => 'even'
     * ```
     */
    function create<I, O = I, S = O>(init: (initHalt: () => void) => S, next: (current: S, next: I, index: number, halt: () => void) => S, stateToResult: (state: S, index: number, halted: boolean) => O): Reducer<I, O>;
    /**
     * Returns a `Reducer` of which the input, state, and output types are the same.
     * @param init - the initial state value
     * @param next - returns the next state value based on the given inputs:<br/>
     * - current: the current state<br/>
     * - next: the current input value<br/>
     * - index: the input index value<br/>
     * - halt: function that, when called, ensures no more elements are passed to the reducer
     * @param stateToResult - (optional) a function that converts the current state to an output value
     * @typeparam T - the overall value type
     * @example
     * ```ts
     * const sum = Reducer.createMono(
     *   0,
     *   (current, value) => current + value
     * );
     * const result = Stream.of(1, 2, 3, 2, 1).reduce(sum);
     * console.log(result);
     * // => 9
     * ```
     */
    function createMono<T>(init: (initHalt: () => void) => T, next: (current: T, next: T, index: number, halt: () => void) => T, stateToResult?: (state: T, index: number, halted: boolean) => T): Reducer<T>;
    /**
     * Returns a `Reducer` of which the state and output types are the same.
     * @param init - the initial state value
     * @param next - returns the next state value based on the given inputs:<br/>
     * - current: the current state<br/>
     * - next: the current input value<br/>
     * - index: the input index value<br/>
     * - halt: function that, when called, ensures no more elements are passed to the reducer
     * @param stateToResult - (optional) a function that converts the current state to an output value
     * @typeparam I - the input value type
     * @typeparam O - the output value type
     * @example
     * ```ts
     * const boolToString = Reducer.createOutput(
     *   '',
     *   (current, value: boolean) => current + (value ? 'T' : 'F')
     * );
     * const result = Stream.of(true, false, true).reduce(boolToString);
     * console.log(result);
     * // => 'TFT'
     * ```
     */
    function createOutput<I, O = I>(init: (initHalt: () => void) => O, next: (current: O, next: I, index: number, halt: () => void) => O, stateToResult?: (state: O, index: number, halted: boolean) => O): Reducer<I, O>;
    /**
     * Returns a `Reducer` that uses the given `init` and `next` values to fold the input values into
     * result values.
     * @param init - an (optionally lazy) initial result value
     * @param next - a function taking the following arguments:<br/>
     * - current - the current result value<br/>
     * - value - the next input value<br/>
     * - index: the input index value<br/>
     * - halt: function that, when called, ensures no more elements are passed to the reducer
     * @typeparam T - the input type
     * @typeparam R - the output type
     */
    function fold<T, R>(init: OptLazy<R>, next: (current: R, value: T, index: number, halt: () => void) => R): Reducer<T, R>;
    /**
     * A `Reducer` that sums all given numeric input values.
     * @example
     * ```ts
     * console.log(Stream.range({ amount: 5 }).reduce(Reducer.sum))
     * // => 10
     * ```
     */
    const sum: Reducer<number, number>;
    /**
     * A `Reducer` that calculates the product of all given numeric input values.
     * @example
     * ```ts
     * console.log(Stream.range({ start: 1, amount: 5 }).reduce(product))
     * // => 120
     * ```
     */
    const product: Reducer<number, number>;
    /**
     * A `Reducer` that calculates the average of all given numberic input values.
     * @example
     * ```ts
     * console.log(Stream.range({ amount: 5 }).reduce(Reducer.average));
     * // => 2
     * ```
     */
    const average: Reducer<number, number>;
    /**
     * Returns a `Reducer` that remembers the minimum value of the inputs using the given `compFun` to compare input values
     * @param compFun - a comparison function for two input values, returning 0 when equal, positive when greater, negetive when smaller
     * @param otherwise - (default: undefineds) a fallback value when there were no input values given
     * @typeparam T - the element type
     * @typeparam O - the fallback value type
     * @example
     * ```ts
     * const stream = Stream.of('abc', 'a', 'abcde', 'ab')
     * console.log(stream.minBy((s1, s2) => s1.length - s2.length))
     * // 'a'
     * ```
     */
    const minBy: {
        <T>(compFun: (v1: T, v2: T) => number): Reducer<T, T | undefined>;
        <T, O>(compFun: (v1: T, v2: T) => number, otherwise: OptLazy<O>): Reducer<T, T | O>;
    };
    /**
     * Returns a `Reducer` that remembers the minimum value of the numberic inputs.
     * @param otherwise - (default: undefined) a fallback value when there were no input values given
     * @typeparam O - the fallback value type
     * @example
     * ```ts
     * console.log(Stream.of(5, 3, 7, 4).reduce(Reducer.min()))
     * // => 3
     * ```
     */
    const min: {
        (): Reducer<number, number | undefined>;
        <O>(otherwise: OptLazy<O>): Reducer<number, number | O>;
    };
    /**
     * Returns a `Reducer` that remembers the maximum value of the inputs using the given `compFun` to compare input values
     * @param compFun - a comparison function for two input values, returning 0 when equal, positive when greater, negetive when smaller
     * @param otherwise - (default: undefined) a fallback value when there were no input values given
     * @typeparam T - the element type
     * @typeparam O - the fallback value type
     * @example
     * ```ts
     * const stream = Stream.of('abc', 'a', 'abcde', 'ab')
     * console.log(stream.maxBy((s1, s2) => s1.length - s2.length))
     * // 'abcde'
     * ```
     */
    const maxBy: {
        <T>(compFun: (v1: T, v2: T) => number): Reducer<T, T | undefined>;
        <T, O>(compFun: (v1: T, v2: T) => number, otherwise: OptLazy<O>): Reducer<T, T | O>;
    };
    /**
     * Returns a `Reducer` that remembers the maximum value of the numberic inputs.
     * @param otherwise - (default: undefined) a fallback value when there were no input values given
     * @typeparam O - the fallback value type
     * @example
     * ```ts
     * console.log(Stream.of(5, 3, 7, 4).reduce(Reducer.max()))
     * // => 7
     * ```
     */
    const max: {
        (): Reducer<number, number | undefined>;
        <O>(otherwise: OptLazy<O>): Reducer<number, number | O>;
    };
    /**
     * Returns a `Reducer` that joins the given input values into a string using the given options.
     * @param options - an object containing:<br/>
     * - sep: (optional) a seperator string value between values in the output<br/>
     * - start: (optional) a start string to prepend to the output<br/>
     * - end: (optional) an end string to append to the output<br/>
     * @typeparam T - the input element type
     * @example
     * ```ts
     * console.log(Stream.of(1, 2, 3).reduce(Reducer.join({ sep: '-' })))
     * // => '1-2-3'
     * ```
     */
    function join<T>({ sep, start, end, valueToString, }?: {
        sep?: string | undefined;
        start?: string | undefined;
        end?: string | undefined;
        valueToString?: ((value: T) => string) | undefined;
    }): Reducer<T, string>;
    /**
     * A `Reducer` that remembers the amount of input items provided.
     * @example
     * ```ts
     * const stream = Stream.range({ amount: 10 })
     * console.log(stream.reduce(Reducer.count))
     * // => 10
     * ```
     */
    const count: Reducer<any, number>;
    /**
     * Returns a `Reducer` that remembers the first input value.
     * @param otherwise - (default: undefined) a fallback value to output if no input value has been provided
     * @typeparam T - the input value type
     * @typeparam O - the fallback value type
     * @example
     * ```ts
     * console.log(Stream.range({ amount: 10 }).reduce(Reducer.first()))
     * // => 0
     * ```
     */
    const first: {
        <T>(): Reducer<T, T | undefined>;
        <T, O>(otherwise: OptLazy<O>): Reducer<T, T | O>;
    };
    /**
     * Returns a `Reducer` that remembers the last input value.
     * @param otherwise - (default: undefined) a fallback value to output if no input value has been provided
     * @typeparam T - the input value type
     * @typeparam O - the fallback value type
     * @example
     * ```ts
     * console.log(Stream.range({ amount: 10 }).reduce(Reducer.last()))
     * // => 9
     * ```
     */
    const last: {
        <T>(): Reducer<T, T | undefined>;
        <T, O>(otherwise: OptLazy<O>): Reducer<T, T | O>;
    };
    /**
     * Returns a Reducer that only produces an output value when having receives exactly one
     * input value, otherwise will return the `otherwise` value or undefined.
     * @param otherwise - the fallback value to return when more or less than one value is received.
     * @typeparam T - the element type
     * @typeparam O - the fallback value type
     */
    const single: {
        <T>(): Reducer<T, T | undefined>;
        <T, O>(otherwise: OptLazy<O>): Reducer<T, T | O>;
    };
    /**
     * Returns a `Reducer` that ouputs false as long as no input value satisfies given `pred`, true otherwise.
     * @typeparam T - the element type
     * @param pred - a function taking an input value and its index, and returning true if the value satisfies the predicate
     * @param options - (optional) an object containing the following properties:<br/>
     * - negate: (default: false) when true will invert the given predicate
     * @example
     * ```ts
     * console.log(
     *   Stream.range({ amount: 10 }).reduce(Reducer.some((v) => v > 5))
     * )
     * // => true
     * ```
     */
    function some<T>(pred: (value: T, index: number) => boolean, options?: {
        negate?: boolean;
    }): Reducer<T, boolean>;
    /**
     * Returns a `Reducer` that ouputs true as long as all input values satisfy the given `pred`, false otherwise.
     * @typeparam T - the element type
     * @param pred - a function taking an input value and its index, and returning true if the value satisfies the predicate
     * @param options - (optional) an object containing the following properties:<br/>
     * - negate: (default: false) when true will invert the given predicate
     * @example
     * ```ts
     * console.log(
     *   Stream.range({ amount: 10 }).reduce(Reducer.every((v) => v < 5))
     * )
     * // => false
     * ```
     */
    function every<T>(pred: (value: T, index: number) => boolean, options?: {
        negate?: boolean;
    }): Reducer<T, boolean>;
    /**
     * Returns a `Reducer` that ouputs true when the received elements match the given `other` stream source according to the `eq` instance, false otherwise.
     * @typeparam T - the element type
     * @param other - a stream source containg elements to match against
     * @param options - (optional) an object containing the following properties:<br/>
     * - eq: (default: Eq.objectIs) the `Eq` instance to use to compare elements
     * - negate: (default: false) when true will invert the given predicate
     */
    function equals<T>(other: StreamSource<T>, options?: {
        eq?: Eq<T>;
        negate?: boolean;
    }): Reducer<T, boolean>;
    /**
     * Returns a `Reducer` that outputs false as long as the given `elem` has not been encountered the given `amount` of times in the input values, true otherwise.
     * @typeparam T - the element type
     * @param elem - the element to search for
     * @param options - (optional) an object containing the following properties:<br/>
     * - amount: (detaulf: 1) the amount of elements to find
     * - eq: (default: Eq.objectIs) the `Eq` instance to use to compare elements
     * - negate: (default: false) when true will invert the given predicate
     * @example
     * ```ts
     * console.log(Stream.range({ amount: 10 }).reduce(Reducer.contains(5)))
     * // => true
     * ```
     */
    function contains<T, T2 extends T = T>(elem: T2, options?: {
        amount?: number;
        eq?: Eq<T | T2>;
        negate?: boolean;
    }): Reducer<T, boolean>;
    /**
     * Returns a `Reducer` that returns true if the first input values match the given `slice` values repeated `amount` times. Otherwise,
     * returns false.
     * @param slice - a sequence of elements to match against
     * @param options - (optional) an object containing the following properties:<br/>
     * - amount: (detaulf: 1) the amount of elements to find
     * - eq: (default: Eq.objectIs) the `Eq` instance to use to compare elements
     */
    function startsWithSlice<T>(slice: StreamSource<T>, options?: {
        eq?: Eq<T> | undefined;
        amount?: number;
    }): Reducer<T, boolean>;
    /**
     * Returns a `Reducer` that returns true if the last input values match the given `slice` values repeated `amount` times. Otherwise,
     * returns false.
     * @param slice - a sequence of elements to match against
     * @param options - (optional) an object containing the following properties:<br/>
     * - amount: (detaulf: 1) the amount of elements to find
     * - eq: (default: Eq.objectIs) the `Eq` instance to use to compare elements
     */
    function endsWithSlice<T>(slice: StreamSource<T>, options?: {
        eq?: Eq<T> | undefined;
        amount?: number;
    }): Reducer<T, boolean>;
    /**
     * Returns a `Reducer` that returns true if the input values contain the given `slice` sequence `amount` times. Otherwise,
     * returns false.
     * @param slice - a sequence of elements to match against
     * @param options - (optional) an object containing the following properties:<br/>
     * - amount: (detaulf: 1) the amount of elements to find
     * - eq: (default: Eq.objectIs) the `Eq` instance to use to compare elements
     */
    function containsSlice<T>(slice: StreamSource<T>, options?: {
        eq?: Eq<T> | undefined;
        amount?: number;
    }): Reducer<T, boolean>;
    /**
     * A `Reducer` that takes boolean values and outputs true if all input values are true, and false otherwise.
     * @example
     * ```ts
     * console.log(Stream.of(true, false, true)).reduce(Reducer.and))
     * // => false
     * ```
     */
    const and: Reducer<boolean, boolean>;
    /**
     * A `Reducer` that takes boolean values and outputs true if one or more input values are true, and false otherwise.
     * @example
     * ```ts
     * console.log(Stream.of(true, false, true)).reduce(Reducer.or))
     * // => true
     * ```
     */
    const or: Reducer<boolean, boolean>;
    /**
     * A `Reducer` that outputs true if no input values are received, false otherwise.
     * @example
     * ```ts
     * console.log(Stream.of(1, 2, 3).reduce(Reducer.isEmpty))
     * // => false
     * ```
     */
    const isEmpty: Reducer<any, boolean>;
    /**
     * A `Reducer` that outputs true if one or more input values are received, false otherwise.
     * @example
     * ```ts
     * console.log(Stream.of(1, 2, 3).reduce(Reducer.nonEmpty))
     * // => true
     * ```
     */
    const nonEmpty: Reducer<any, boolean>;
    /**
     * Returns a `Reducer` that always outputs the given `value`, and does not accept input values.
     */
    function constant<T>(value: OptLazy<T>): Reducer<any, T>;
    /**
     * Returns a `Reducer` that splits the incoming values into two separate outputs based on the given `pred` predicate. Values for which the predicate is true
     * are fed into the `collectorTrue` reducer, and other values are fed into the `collectorFalse` instance. If no collectors are provided the values are collected
     * into arrays.
     * @param pred - a predicate receiving the value and its index
     * @param options - (optional) an object containing the following properties:<br/>
     * - collectorTrue: (default: Reducer.toArray()) a reducer that collects the values for which the predicate is true<br/>
     * - collectorFalse: (default: Reducer.toArray()) a reducer that collects the values for which the predicate is false
     * @typeparam T - the input element type
     * @typeparam RT - the reducer result type for the `collectorTrue` value
     * @typeparam RF - the reducer result type for the `collectorFalse` value
     * @note if the predicate is a type guard, the return type is automatically inferred
     * @example
     * ```ts
     * Stream.of(1, 2, 3).partition((v) => v % 2 === 0)
     * // => [[2], [1, 3]]
     *
     * Stream.of<number | string>(1, 'a', 'b', 2)
     *   .partition((v): v is string => typeof v === 'string')
     * // => [['a', 'b'], [1, 2]]
     * // return type is: [string[], number[]]
     *
     * Stream.of(1, 2, 3, 4).partition(
     *   (v) => v % 2 === 0,
     *   { collectorTrue: Reducer.toJSSet(), collectorFalse: Reducer.sum }
     * )
     * // => [Set(2, 4), 4]
     * ```
     */
    const partition: {
        <T, T2 extends T, RT, RF = RT>(pred: (value: T, index: number) => value is T2, options: {
            collectorTrue: Reducer<T2, RT>;
            collectorFalse: Reducer<Exclude<T, T2>, RF>;
        }): Reducer<T, [true: RT, false: RF]>;
        <T, T2 extends T>(pred: (value: T, index: number) => value is T2, options?: {
            collectorTrue?: undefined;
            collectorFalse?: undefined;
        }): Reducer<T, [true: T2[], false: Exclude<T, T2>[]]>;
        <T, RT, RF = RT>(pred: (value: T, index: number) => boolean, options: {
            collectorTrue: Reducer<T, RT>;
            collectorFalse: Reducer<T, RF>;
        }): Reducer<T, [true: RT, false: RF]>;
        <T>(pred: (value: T, index: number) => boolean, options?: {
            collectorTrue?: undefined;
            collectorFalse?: undefined;
        }): Reducer<T, [true: T[], false: T[]]>;
    };
    /**
     * Returns a `Reducer` that uses the `valueToKey` function to calculate a key for each value, and feeds the tuple of the key and the value to the
     * `collector` reducer. Finally, it returns the output of the `collector`. If no collector is given, the default collector will return a JS multimap
     * of the type `Map<K, V[]>`.
     * @param valueToKey - function taking a value and its index, and returning the corresponding key
     * @param options - (optional) an object containing the following properties:<br/>
     * - collector: (default: Reducer.toArray()) a reducer that collects the incoming tuple of key and value, and provides the output
     * @typeparam T - the input value type
     * @typeparam K - the key type
     * @typeparam R - the collector output type
     * @example
     * ```ts
     * Stream.of(1, 2, 3).groupBy((v) => v % 2)
     * // => Map {0 => [2], 1 => [1, 3]}
     * ```
     */
    const groupBy: {
        <T, K, R, T2 extends readonly [K, T] = [K, T]>(valueToKey: (value: T, index: number) => K, options: {
            collector: Reducer<[K, T] | T2, R>;
        }): Reducer<T, R>;
        <T, K>(valueToKey: (value: T, index: number) => K, options?: {
            collector?: undefined;
        }): Reducer<T, Map<K, T[]>>;
    };
    /**
     * Returns a `Reducer` that feeds incoming values to all reducers in the provided `reducers` source, and halts when the first
     * reducer in the array is halted and returns the output of that reducer. Returns the `otherwise` value if no reducer is yet halted.
     * @param reducers - a stream source of reducers that will receive the incoming values
     * @param otherwise - a fallback value to return if none of the reducers has been halted
     * @typeparam T - the input value type
     * @typeparam R - the output value type
     * @typeparam O - the fallback value type
     */
    const race: {
        <T, R, O>(reducers: StreamSource<Reducer<T, R>>, otherwise: OptLazy<O>): Reducer<T, R | O>;
        <T, R>(reducers: StreamSource<Reducer<T, R>>): Reducer<T, R | undefined>;
    };
    /**
     * Returns a `Reducer` that collects received input values in an array, and returns a copy of that array as an output value when requested.
     * @typeparam T - the element type
     * @param options - (optional) object specifying the following properties<br/>
     * - reversed: (optional) when true will create a reversed array
     * @example
     * ```ts
     * console.log(Stream.of(1, 2, 3).reduce(Reducer.toArray()))
     * // => [1, 2, 3]
     * console.log(Stream.of(1, 2, 3).reduce(Reducer.toArray({ reversed: true })))
     * // => [3, 2, 1]
     * ```
     */
    function toArray<T>(options?: {
        reversed?: boolean;
    }): Reducer<T, T[]>;
    /**
     * Returns a `Reducer` that collects received input tuples into a mutable JS Map, and returns
     * a copy of that map when output is requested.
     * @typeparam K - the map key type
     * @typeparam V - the map value type
     * @example
     * ```ts
     * console.log(Stream.of([1, 'a'], [2, 'b']).reduce(Reducer.toJSMap()))
     * // Map { 1 => 'a', 2 => 'b' }
     * ```
     */
    function toJSMap<K, V>(): Reducer<readonly [K, V], Map<K, V>>;
    /**
     * Returns a `Reducer` that collects received input tuples into a mutable JS multimap, and returns
     * a copy of that map when output is requested.
     * @typeparam K - the map key type
     * @typeparam V - the map value type
     * @example
     * ```ts
     * console.log(Stream.of([1, 'a'], [2, 'b']).reduce(Reducer.toJSMap()))
     * // Map { 1 => 'a', 2 => 'b' }
     * ```
     */
    function toJSMultiMap<K, V>(): Reducer<readonly [K, V], Map<K, V[]>>;
    /**
     * Returns a `Reducer` that collects received input values into a mutable JS Set, and returns
     * a copy of that map when output is requested.
     * @typeparam T - the element type
     * @example
     * ```ts
     * console.log(Stream.of(1, 2, 3).reduce(Reducer.toJSSet()))
     * // Set {1, 2, 3}
     * ```
     */
    function toJSSet<T>(): Reducer<T, Set<T>>;
    /**
     * Returns a `Reducer` that collects 2-tuples containing keys and values into a plain JS object, and
     * returns a copy of that object when output is requested.
     * @typeparam K - the result object key type
     * @typeparam V - the result object value type
     * @example
     * ```ts
     * console.log(Stream.of(['a', 1], ['b', true]).reduce(Reducer.toJSObject()))
     * // { a: 1, b: true }
     * ```
     */
    function toJSObject<K extends string | number | symbol, V>(): Reducer<readonly [K, V], Record<K, V>>;
    /**
     * Type defining the allowed shape of reducer combinations.
     * @typeparam T - the input type
     */
    type CombineShape<T> = Reducer<T, any> | Reducer.CombineShape<T>[] | {
        [key: string]: Reducer.CombineShape<T>;
    };
    /**
     * Type defining the result type of a reducer combination for a given shape.
     * @typeparam S - the reducer combination shape
     */
    type CombineResult<S extends Reducer.CombineShape<any>> = S extends readonly Reducer.CombineShape<any>[] ? 0 extends S['length'] ? Reducer.CombineResult<S[number]>[] : {
        [K in keyof S]: S[K] extends Reducer.CombineShape<any> ? Reducer.CombineResult<S[K]> : never;
    } : S extends {
        [key: string]: Reducer.CombineShape<any>;
    } ? {
        [K in keyof S]: Reducer.CombineResult<S[K]>;
    } : S extends Reducer<any, infer R> ? R : never;
    class InvalidCombineShapeError extends ErrBase.CustomError {
        constructor();
    }
    class ReducerHaltedError extends ErrBase.CustomError {
        constructor();
    }
    /**
     * Returns a `Reducer` that combines multiple input `reducers` according to the given "shape" by providing input values to all of them and collecting the outputs in the shape.
     * @typeparam T - the input value type for all the reducers
     * @typeparam S - the desired result shape type
     * @param shape - a shape defining where reducer outputs will be located in the result. It can consist of a single reducer, an array of shapes, or an object with string keys and shapes as values.
     * @example
     * ```ts
     * const red = Reducer.combine([Reducer.sum, { av: [Reducer.average] }])
     * console.log(Stream.range({amount: 9 }).reduce(red))
     * // => [36, { av: [4] }]
     * ```
     */
    function combine<T, const S extends Reducer.CombineShape<T>>(shape: S & Reducer.CombineShape<T>): Reducer<T, Reducer.CombineResult<S>>;
    /**
     * Returns a `Reducer` instance that first applies this reducer, and then applies the given `next` reducer to each output produced
     * by the previous reducer.
     * @typeparam I - the input type of the `reducer1` reducer
     * @typeparam O1 - the output type of the `reducer1` reducer
     * @typeparam O2 - the output type of the `reducer2` reducer
     * @typeparam O3 - the output type of the `reducer3` reducer
     * @typeparam O4 - the output type of the `reducer4` reducer
     * @typeparam O5 - the output type of the `reducer5` reducer
     * @param reducer1 - the next reducer to apply to each output of this reducer.
     * @param reducer2 - (optional) the next reducer to apply to each output of this reducer.
     * @param reducer3 - (optional) the next reducer to apply to each output of this reducer.
     * @param reducer4 - (optional) the next reducer to apply to each output of this reducer.
     * @param reducer5 - (optional) the next reducer to apply to each output of this reducer.
     * @example
     * ```ts
     * Stream.of(1, 2, 3)
     *  .reduce(
     *    Reducer.pipe(Reducer.product, Reducer.sum)
     *  )
     * // => 9
     * ```
     */
    const pipe: {
        <I, O1, O2>(reducer1: Reducer<I, O1>, reducer2: Reducer<O1, O2>): Reducer<I, O2>;
        <I, O1, O2, O3>(reducer1: Reducer<I, O1>, reducer2: Reducer<O1, O2>, reducer3: Reducer<O2, O3>): Reducer<I, O3>;
        <I, O1, O2, O3, O4>(reducer1: Reducer<I, O1>, reducer2: Reducer<O1, O2>, reducer3: Reducer<O2, O3>, reducer4: Reducer<O2, O4>): Reducer<I, O4>;
        <I, O1, O2, O3, O4, O5>(reducer1: Reducer<I, O1>, reducer2: Reducer<O1, O2>, reducer3: Reducer<O2, O3>, reducer4: Reducer<O2, O4>, reducer5: Reducer<O2, O5>): Reducer<I, O5>;
    };
}
