import { type IsAnyFunc, type IsArray, type IsPlainObj } from '@rimbu/base';
import type { Protected } from './internal.cjs';
import type { Tuple } from './tuple.cjs';
/**
 * A type to determine the allowed input type for the `patch` function.
 * @typeparam T - the input type to be patched
 */
export type Patch<T, C = T> = Patch.Entry<T, C, T, T>;
export declare namespace Patch {
    /**
     * The entry type for a (nested) patch. Can be either a patch object or a function accepting the nested patch function and returning a patch object.
     * @typeparam T - the input value type
     * @typeparam C - a utility type
     * @typeparam P - the parent type
     * @typeparam R - the root object type
     */
    type Entry<T, C, P, R> = IsAnyFunc<T> extends true ? T : IsPlainObj<T> extends true ? Patch.WithResult<T, P, R, Patch.Obj<T, C, R>> : Tuple.IsTuple<T> extends true ? Patch.WithResult<T, P, R, T | Patch.Tup<T, C, R>> : IsArray<T> extends true ? Patch.WithResult<T, P, R, T> : Patch.WithResult<T, P, R, T>;
    /**
     * Either result type S, or a patch function with the value type, the parent type, and the root type.
     * @typeparam T - the value type
     * @typeparam P - the parent type
     * @typeparam R - the root type
     * @typeparam S - the result type
     */
    type WithResult<T, P, R, S> = S | Patch.Func<T, P, R, S>;
    /**
     * A function patch type that is a function taking the current value, the parent and root values,
     * and returns a return value.
     * @typeparam T - the value type
     * @typeparam P - the parent type
     * @typeparam R - the root type
     * @typeparam S - the result type
     */
    type Func<T, P, R, S> = (current: Protected<T>, parent: Protected<P>, root: Protected<R>) => Protected<S>;
    /**
     * A type defining the allowed patch values for tuples.
     * @typeparam T - the input tuple type
     * @typeparam C - a utility type
     * @typeparam R - the root type
     */
    type Tup<T, C, R> = {
        [K in Tuple.KeysOf<T>]?: Patch.Entry<T[K & keyof T], C[K & keyof C], T, R>;
    } & NotIterable;
    /**
     * Utility type to exclude Iterable types.
     */
    type NotIterable = {
        [Symbol.iterator]?: never;
    };
    /**
     * A type defining the allowed patch values for objects.
     * @typeparam T - the input value type
     * @typeparam C - a utility type
     * @typeparam R - the root object type
     */
    type Obj<T, C, R> = T | Patch.ObjProps<T, C, R>[];
    /**
     * A type defining the allowed patch values for object properties.
     * @typeparam T - the input value type
     * @typeparam C - a utility type
     * @typeparam R - the root object type
     */
    type ObjProps<T, C, R> = {
        [K in keyof C]?: K extends keyof T ? Patch.Entry<T[K], C[K], T, R> : never;
    };
}
/**
 * Returns an immutably updated version of the given `value` where the given `patchItems` have been
 * applied to the result.
 * The Rimbu patch notation is as follows:
 * - if the target is a simple value or array, the patch can be the same type or a function returning the same type
 * - if the target is a tuple (array of fixed length), the patch be the same type or an object containing numeric keys with patches indicating the tuple index to patch
 * - if the target is an object, the patch can be the same type, or an array containing partial keys with their patches for the object
 * @typeparam T - the type of the value to patch
 * @typeparam TE - a utility type
 * @typeparam TT - a utility type
 * @param value - the input value to patch
 * @param patchItem - the `Patch` value to apply to the input value
 * @example
 * ```ts
 * const input = { a: 1, b: { c: true, d: 'a' } }
 * patch(input, [{ a: 2 }])  // => { a: 2, b: { c: true, d: 'a' } }
 * patch(input, [{ b: [{ c: (v) => !v }] }] )
 * // => { a: 1, b: { c: false, d: 'a' } }
 * patch(input, [{ a: (v) => v + 1, b: [{ d: 'q' }] }] )
 * // => { a: 2, b: { c: true, d: 'q' } }
 * ```
 */
export declare function patch<T, TE extends T = T, TT = T>(value: T, patchItem: Patch<TE, T & TT>): T;
