/**
 * A functional version of the cancellation token pattern for making cancellable async functions.
 * @remarks
 *
 * The {@link CancellableAsyncFn} takes a {@link RaceCancelFn} function that will build the cancellation race lazily.
 *
 * This avoids a number of issues around cleanup and unhandled rejections and as well as being easy to adapt other
 * cancellation implementations for interop.
 * @packageDocumentation
 */


/**
 * An async function.
 * @public
 */
export declare type AsyncFn<TResult> = () => PromiseLike<TResult>;

/**
 * The Error interface for cancellation rejection.
 * @public
 */
export declare interface CancelError<TName extends string = "CancelError"> extends Error {
    name: TName;
    isCancelled: true;
}

/**
 * A executor function for the cancellation.
 * @public
 */
export declare type CancelExecutorFn = (resolve: () => void) => void;

/**
 * A cancellable async function.
 * @param raceCancel - a {@link RaceCancelFn}.
 * @public
 */
export declare type CancellableAsyncFn<TResult> = (raceCancel: RaceCancelFn) => Promise<TResult>;

/**
 * Creates a cancellable Promise from an executor that returns a {@link DisposeFn} function and a {@link RaceCancelFn} function.
 *
 * @param disposableExecutor - a {@link DisposableExecutorFn} function (this will not be run if already cancelled).
 * @param raceCancel - a {@link RaceCancelFn} function to race against the disposable promise against.
 * @public
 */
export declare function cancellablePromise<TResult>(disposableExecutor: DisposableExecutorFn<TResult>, raceCancel?: RaceCancelFn): Promise<TResult>;

/**
 * A {@link CancelError} or `string` that is the cancellation reason.
 * @public
 */
export declare type CancelReason = CancelError<string> | string;

/**
 * Returns a {@link RaceCancelFn} function that is the composition of the two RaceCancel functions.
 *
 * @remarks
 * For convenience of writing methods that take cancellations, the params
 * are optional. If a is undefined, then b is retuned, if b is undefined then a
 * is returned, and if they both are undefined a noop race that just invokes
 * the task is returned.
 *
 * The outer scope function is expected to be a wider concern like ctrl-C and the inner a narrower
 * concern like timeout. This way if you catch a error then try to say sleep before a retrying the narrower
 * concern the outer will bail out without even starting the timeout because it is already cancelled.
 *
 * This isn't a hard requirement just things are optimized with that assunmption.
 *
 * @param inner - a {@link RaceCancelFn} function that is the inner function of the composition, in general its cancellation scope should be narrower than the outer scope.
 * @param outer - a {@link RaceCancelFn} function that is the outer function, its scope should be wider or equal to the inner scope.
 * @public
 */
export declare function composeRaceCancel(inner?: RaceCancelFn, outer?: RaceCancelFn): RaceCancelFn;

/**
 * Create a tuple of {@link RaceCancelFn} and {@link ResolveCancelFn} functions.
 *
 * @remarks
 * In general, it is better to use {@link race-cancellation#withCancel} to scope cancellation
 * to an async task so that the cancellation concern is cleaned up.
 *
 * If the cancellation concern will be GC'ed with the cancel already and no cleanup
 * needed like removing an event listener than this method can be simpler.
 * @public
 */
export declare function deferCancel(): [RaceCancelFn, ResolveCancelFn];

/**
 * A executor function for the cancellation concern that can resolve with a reason
 * and can return a cleanup function.
 * @public
 */
export declare type DisposableCancelExecutorFn = (resolve: ResolveCancelFn) => DisposeFn;

/**
 * A promise executor that returns a {@link DisposeFn} function.
 *
 * @remarks
 *
 * For example, if it is the promise of a setTimeout, should call clearTimeout.
 *
 * If it resolves on an event listener, it should uninstall the event listener.
 * @public
 */
export declare type DisposableExecutorFn<TResult> = (resolve: (value?: TResult | PromiseLike<TResult>) => void, reject: (reason?: unknown) => void) => DisposeFn;

/**
 * A cleanup function that should be idempotent and infallible.
 * @public
 */
export declare type DisposeFn = () => void;

/**
 * An accessor function for checking cancelled state.
 * @public
 */
export declare type IsCancelledFn = () => boolean;

/**
 * Create a {@link RaceCancelFn} function.
 *
 * @param isCancelled - a function that returns whether or not we are currently cancelled
 * @param executor - a callback to resolve the cancellation
 * @param cancelReason - an optional reason for the cancellation
 * @public
 */
export declare function newRaceCancel(isCancelled: IsCancelledFn, executor: CancelExecutorFn, cancelReason?: (() => CancelReason | undefined) | CancelReason): RaceCancelFn;

/**
 * A no-op implemenation of a {@link RaceCancelFn} function.
 *
 * @remarks
 * Allows an async function to add cancellation support in a backwards compatible way by
 * adding optional param by providing this as a default.
 *
 * @param asyncFnOrPromise - an {@link AsyncFn} or `PromiseLike` that will be resolved.
 * @public
 */
export declare const noopRaceCancel: RaceCancelFn;

/**
 * A function that builds a race against a cancel rejection.
 *
 * @remarks
 * If the task is a function, the expectation is it will not be called
 * if already in a cancelled state. Thus it should not close over any
 * floating promises, in general it should just create a new promise,
 * if it uses a cached promise it should have been already chained
 * to something that handles its rejection.
 *
 * This method can also take a promise and it will always race it even
 * if already in a cancelled state so if the promise fails it will not
 * cause an unhandled rejection.
 *
 * Calling this function is infallible (it wont fail to return a Promise
 * to be awaited).
 *
 * @param asyncFnOrPromise - a {@link AsyncFn} function to start an async operation or a promise.
 * @public
 */
export declare type RaceCancelFn = <TResult>(asyncFnOrPromise: AsyncFn<TResult> | PromiseLike<TResult>) => Promise<TResult>;

/**
 * A function that resolves the cancellation for deferCancel or withCancel.
 * @public
 */
export declare type ResolveCancelFn = (reason?: CancelReason) => void;

/**
 * The Error interface for {@link withTimeout} if the timeout wins the race.
 * @public
 */
export declare interface TimeoutError<TName extends string = "TimeoutError"> extends CancelError<TName> {
    isTimeout: true;
}

/**
 * Run a {@link CancellableAsyncFn} function with a {@link RaceCancelFn} adapted from a {@link DisposableCancelExecutorFn} function.
 *
 * @param cancellableAsync - a {@link CancellableAsyncFn} function
 * @param disposableCancelExecutor - a {@link DisposableCancelExecutorFn} function that will only be called once
 * @param outerRaceCancel - an optional outer {@link RaceCancelFn} function that will be composed with the {@link RaceCancelFn} function before being passed to the {@link CancellableAsyncFn} function.
 * @public
 */
export declare function withCancel<TResult>(cancellableAsync: CancellableAsyncFn<TResult>, disposableCancelExecutor: DisposableCancelExecutorFn, outerRaceCancel?: RaceCancelFn): Promise<TResult>;

/**
 * Wrap a {@link CancellableAsyncFn} function to cancel still pending concurrent child {@link CancellableAsyncFn}
 * functions when another concurrent promise either rejected in a Promise.all() or won in a Promise.race().
 *
 * @param cancellableAsync - a {@link CancellableAsyncFn} function to run with cancel pending
 * @param outerRaceCancel - an optional outer {@link RaceCancelFn} function
 * @public
 */
export declare function withCancelPending<TResult>(cancellableAsync: CancellableAsyncFn<TResult>, outerRaceCancel?: RaceCancelFn): Promise<TResult>;

/**
 * Wrap a cancellable async function with a timeout.
 *
 * @remarks
 *
 * @example
 * ```js
 * async function fetchWithTimeout(url, timeoutMs, raceCancel) {
 *   return await withTimeout((raceTimeout) => cancellableFetch(url, raceTimeout), timeoutMs, raceCancel);
 * }
 * ```
 *
 * @param cancellableAsync - a {@link CancellableAsyncFn} function
 * @param milliseconds - a timeout in miliseconds
 * @param raceCancel - an optional outer scope {@link RaceCancelFn} function that will be combined with the timeout race before being passed to the {@link CancellableAsyncFn} function
 * @public
 */
export declare function withTimeout<TResult>(cancellableAsync: CancellableAsyncFn<TResult>, milliseconds: number, raceCancel?: RaceCancelFn): Promise<TResult>;

export { }
