import { Box, Deferred, Disposer } from '@hazae41/box';
import { Nullable } from '@hazae41/option';
import { Plume } from '@hazae41/plume';
import { Result } from '@hazae41/result';

declare class EmptyPoolError extends Error {
    #private;
    readonly name: string;
    constructor();
}
declare class EmptySlotError extends Error {
    #private;
    readonly name: string;
    constructor();
}
declare class Indexed<T extends Disposable> {
    readonly index: number;
    readonly value: T;
    constructor(index: number, value: T);
    [Symbol.dispose](): void;
    get(): T;
}
declare class PoolItem<T extends Disposable> extends Box<Indexed<T>> {
    readonly pool: Pool<T>;
    readonly value: Indexed<T>;
    readonly clean: Deferred;
    constructor(pool: Pool<T>, value: Indexed<T>, clean: Deferred);
    [Symbol.dispose](): void;
    moveOrNull(): Box<Indexed<T>> | undefined;
    moveOrThrow(): Box<Indexed<T>>;
    unwrapOrNull(): Indexed<T> | undefined;
    unwrapOrThrow(): Indexed<T>;
    returnOrThrow(): void;
}
type PoolEvents = {
    update: (index: number) => void;
};
declare class Pool<T extends Disposable> {
    #private;
    readonly events: Plume.SuperEventTarget<PoolEvents>;
    /**
     * A pool of disposable items
     */
    constructor();
    [Symbol.iterator](): IterableIterator<Result<PoolItem<T>>>;
    [Symbol.dispose](): void;
    /**
     * Set the entry at the given index and return it
     * @param index
     * @param result
     * @returns
     */
    set(index: number, result: Result<Disposer<T>, Error>): void;
    /**
     * Delete the entry at the given index and return it
     * @param index
     * @returns
     */
    delete(index: number): void;
    update(index: number): void;
    /**
     * Get the entry at the given index or null if empty
     * @param index
     * @returns
     */
    getAnyOrNull(index: number): Nullable<Result<PoolItem<T>>>;
    /**
     * Get the entry at the given index or throw if empty
     * @param index
     * @returns
     */
    getAnyOrThrow(index: number): Result<PoolItem<T>>;
    /**
     * Get the item at the given index or null if empty or errored
     * @param index
     * @returns
     */
    getOrNull(index: number): Nullable<PoolItem<T>>;
    /**
     * Get the item at the given index or throw if empty or errored
     * @param index
     * @returns
     */
    getOrThrow(index: number): PoolItem<T>;
    /**
     * Get a random item or null if none available
     * @returns
     */
    getRandomOrNull<U>(filter: (x: Result<PoolItem<T>>) => Nullable<U>): Nullable<U>;
    /**
     * Get a random item or throw if none available
     * @returns
     */
    getRandomOrThrow<U>(filter: (x: Result<PoolItem<T>>) => Nullable<U>): U;
    /**
     * Get a crypto-random item or null if none available
     * @returns
     */
    getCryptoRandomOrNull<U>(filter: (x: Result<PoolItem<T>>) => Nullable<U>): Nullable<U>;
    /**
     * Get a crypto-random item or throw if none available
     * @returns
     */
    getCryptoRandomOrThrow<U>(filter: (x: Result<PoolItem<T>>) => Nullable<U>): U;
    waitOrThrow<U>(index: number, filter: (x: Nullable<Result<PoolItem<T>>>) => Nullable<U>, signal?: AbortSignal): Promise<U>;
    waitRandomOrThrow<U>(filter: (x: Nullable<Result<PoolItem<T>>>) => Nullable<U>, signal?: AbortSignal): Promise<U>;
    waitCryptoRandomOrThrow<U>(filter: (x: Nullable<Result<PoolItem<T>>>) => Nullable<U>, signal?: AbortSignal): Promise<U>;
}
type PoolCreator<T> = (index: number, signal: AbortSignal) => Promise<Disposer<T>>;
declare class StartPool<T extends Disposable> extends Pool<T> {
    #private;
    /**
     * A pool of startable items
     */
    constructor();
    [Symbol.dispose](): void;
    /**
     * Start the given index
     * @param index
     * @returns
     */
    start(index: number, creator: PoolCreator<T>): void;
    /**
     * Abort the given index
     * @param index
     * @returns
     */
    abort(index: number): void;
}
declare class AutoPool<T extends Disposable> extends StartPool<T> {
    #private;
    readonly creator: PoolCreator<T>;
    readonly capacity: number;
    /**
     * An automatic pool or startable items
     * @param creator
     * @param capacity
     * @returns
     */
    constructor(creator: PoolCreator<T>, capacity: number);
    [Symbol.dispose](): void;
    set(index: number, result: Result<Disposer<T>, Error>): never;
    start(index: number, creator: PoolCreator<T>): never;
    abort(index: number): never;
    delete(index: number): void;
}

export { AutoPool, EmptyPoolError, EmptySlotError, Indexed, Pool, type PoolCreator, type PoolEvents, PoolItem, StartPool };
