/**
 * Listener callback type, used in {@link Emitter.add}.
 */
export type ListenerCallback<T extends unknown[] = void[]> = (...data: T) => void;
/**
 * Registration options for a listener in an {@link Emitter}.
 */
export interface ListenerOptions {
    /**
     * Listener identifier. This is used to find and remove the listener
     * without needing the callback reference.
     *
     * The identifier can be any type. However, remember that the comparison will be
     * by-value for primitive types (string, number), but by reference for objects.
     *
     * For more information, please look at the {@link Emitter.remove} method.
     */
    id: any | undefined;
    /**
     * If `true`, the listener is automatically removed after it's invoked.
     * Defaults to `false`.
     */
    once: boolean;
}
/** Internal listener type. */
type Listener<T extends unknown[]> = ListenerOptions & {
    callback: ListenerCallback<T>;
};
/**
 * Event emitter.
 *
 * This class allows to register listeners that will get notified by the emitter.
 *
 * Usage example:
 *
 * ```js
 * // `onPreRender` is an `Emitter` instance.
 * scene.onPreRender.add(() => console.log('before rendering'));
 * // `onPostRender` is an `Emitter` instance.
 * scene.onPostRender.add(() => console.log('after rendering'));
 * ```
 *
 * You can create your own emitters:
 *
 * ```js
 * import {Emitter} from '@wonderlandengine/api';
 *
 * const emitter = new Emitter();
 * ```
 *
 * You can notify listeners in to your emitter using {@link Emitter.notify}:
 *
 * ```js
 * // Notifies all the listeners.
 * emitter.notify();
 * // Notifies all the listeners with some data.
 * emitter.notify({ myInt: 42, myStr: 'Hello World!' });
 * ```
 *
 * @category event
 */
export declare class Emitter<T extends unknown[] = void[]> {
    /**
     * List of listeners to trigger when `notify` is called.
     *
     * @hidden
     */
    protected readonly _listeners: Listener<T>[];
    /**
     * `true` if the emitter is currently notifying listeners. This
     * is used to defer addition and removal.
     *
     * @hidden
     */
    private _notifying;
    /**
     * Pending additions / removals, performed during a notification.
     *
     * @hidden
     */
    private readonly _transactions;
    /**
     * Register a new listener to be triggered on {@link Emitter.notify}.
     *
     * Basic usage:
     *
     * ```js
     * emitter.add((data) => {
     *     console.log('event received!');
     *     console.log(data);
     * });
     * ```
     *
     * Automatically remove the listener when an event is received:
     *
     * ```js
     * emitter.add((data) => {
     *     console.log('event received!');
     *     console.log(data);
     * }, {once: true});
     * ```
     *
     * @param listener The callback to register.
     * @param opts The listener options. For more information, please have a look
     *     at the {@link ListenerOptions} interface.
     *
     * @returns Reference to self (for method chaining)
     */
    add(listener: ListenerCallback<T>, opts?: Partial<ListenerOptions>): this;
    /**
     * Equivalent to {@link Emitter.add}.
     *
     * @param listeners The callback(s) to register.
     * @returns Reference to self (for method chaining).
     *
     * @deprecated Please use {@link Emitter.add} instead.
     */
    push(...listeners: ListenerCallback<T>[]): this;
    /**
     * Register a new listener to be triggered on {@link Emitter.notify}.
     *
     * Once notified, the listener will be automatically removed.
     *
     * The method is equivalent to calling {@link Emitter.add} with:
     *
     * ```js
     * emitter.add(listener, {once: true});
     * ```
     *
     * @param listener The callback to register.
     *
     * @returns Reference to self (for method chaining).
     */
    once(listener: ListenerCallback<T>): this;
    /**
     * Remove a registered listener.
     *
     * Usage with a callback:
     *
     * ```js
     * const listener = (data) => console.log(data);
     * emitter.add(listener);
     *
     * // Remove using the callback reference:
     * emitter.remove(listener);
     * ```
     *
     * Usage with an id:
     *
     * ```js
     * emitter.add((data) => console.log(data), {id: 'my-callback'});
     *
     * // Remove using the id:
     * emitter.remove('my-callback');
     * ```
     *
     * Using identifiers, you will need to ensure your value is unique to avoid
     * removing listeners from other libraries, e.g.,:
     *
     * ```js
     * emitter.add((data) => console.log(data), {id: 'non-unique'});
     * // This second listener could be added by a third-party library.
     * emitter.add((data) => console.log('Hello From Library!'), {id: 'non-unique'});
     *
     * // Ho Snap! This also removed the library listener!
     * emitter.remove('non-unique');
     * ```
     *
     * The identifier can be any type. However, remember that the comparison will be
     * by-value for primitive types (string, number), but by reference for objects.
     *
     * Example:
     *
     * ```js
     * emitter.add(() => console.log('Hello'), {id: {value: 42}});
     * emitter.add(() => console.log('World!'), {id: {value: 42}});
     * emitter.remove({value: 42}); // None of the above listeners match!
     * emitter.notify(); // Prints 'Hello' and 'World!'.
     * ```
     *
     * Here, both emitters have id `{value: 42}`, but the comparison is made by reference. Thus,
     * the `remove()` call has no effect. We can make it work by doing:
     *
     * ```js
     * const id = {value: 42};
     * emitter.add(() => console.log('Hello'), {id});
     * emitter.add(() => console.log('World!'), {id});
     * emitter.remove(id); // Same reference, it works!
     * emitter.notify(); // Doesn't print.
     * ```
     *
     * @param listener The registered callback or a value representing the `id`.
     *
     * @returns Reference to self (for method chaining)
     */
    remove(listener: ListenerCallback<T> | any): this;
    /**
     * Check whether the listener is registered.
     *
     * @note This method performs a linear search.
     *
     * * @note Doesn't account for pending listeners, i.e.,
     * listeners added / removed during a notification.
     *
     * @param listener The registered callback or a value representing the `id`.
     * @returns `true` if the handle is found, `false` otherwise.
     */
    has(listener: ListenerCallback<T> | any): boolean;
    /**
     * Notify listeners with the given data object.
     *
     * @note This method ensures all listeners are called even if
     * an exception is thrown. For (possibly) faster notification,
     * please use {@link Emitter.notifyUnsafe}.
     *
     * @param data The data to pass to listener when invoked.
     */
    notify(...data: T): void;
    /**
     * Notify listeners with the given data object.
     *
     * @note Because this method doesn't catch exceptions, some listeners
     * will be skipped on a throw. Please use {@link Emitter.notify} for safe
     * notification.
     *
     * @param data The data to pass to listener when invoked.
     */
    notifyUnsafe(...data: T): void;
    /**
     * Return a promise that will resolve on the next event.
     *
     * @note The promise might never resolve if no event is sent.
     *
     * @returns A promise that resolves with the data passed to
     *     {@link Emitter.notify}.
     */
    promise(): Promise<T>;
    /**
     * Number of listeners.
     *
     * @note Doesn't account for pending listeners, i.e.,
     * listeners added / removed during a notification.
     */
    get listenerCount(): number;
    /** `true` if it has no listeners, `false` otherwise. */
    get isEmpty(): boolean;
    /**
     * Flush all pending transactions.
     *
     * @hidden
     */
    private _flushTransactions;
}
/**
 * Registration options for a listener in an {@link RetainEmitter}.
 *
 * Those options extend {@link ListenerOptions}.
 */
export interface RetainListenerOptions extends ListenerOptions {
    /**
     * If `true`, directly resolves if the emitter retains a value. If `false`,
     * the listener isn't invoked until the next {@link Emitter.notify}.
     *
     * Defaults to `true`.
     */
    immediate: boolean;
}
declare const RetainEmitterUndefined: Record<any, unknown>;
/**
 * Event emitter that retains event data when notified.
 *
 * After a notification happens, subsequent calls to {@link RetainEmitter.add} will get
 * automatically notified.
 *
 * You can use another emitter in order to cancel the last retained event:
 *
 * ```js
 * import {Emitter, RetainedEmitter} from '@wonderlandengine/api';
 *
 * const onStart = new RetainedEmitter();
 *
 * onStart.notify(42);
 * onStart.add((data) => console.log(data)) // Prints '42'.
 * ```
 *
 * You can reset the state of the emitter, i.e., making it forget about the
 * last event using:
 *
 * ```js
 * import {Emitter, RetainedEmitter} from '@wonderlandengine/api';
 *
 * const onStart = new RetainedEmitter();
 * onStart.notify(42);
 * onStart.add((data) => console.log(data)) // Prints '42'.
 *
 * // Reset the state of the emitter.
 * onStart.reset();
 * onStart.add((data) => console.log(data)) // Doesn't print anything.
 * ```
 *
 * For more information about emitters, please have a look at the base {@link Emitter} class.
 *
 * @category event
 */
export declare class RetainEmitter<T extends unknown[] = void[]> extends Emitter<T> {
    /** Pre-resolved data. @hidden */
    protected _event: T | typeof RetainEmitterUndefined;
    /**
     * Emitter target used to reset the state of this emitter.
     *
     * @hidden
     */
    protected readonly _reset: Emitter<any> | undefined;
    /** @override */
    add(listener: ListenerCallback<T>, opts?: Partial<RetainListenerOptions>): this;
    /**
     * @override
     *
     * @param listener The callback to register.
     * @param immediate If `true`, directly resolves if the emitter retains a value.
     *
     * @returns Reference to self (for method chaining).
     */
    once(listener: ListenerCallback<T>, immediate?: boolean): this;
    /** @override */
    notify(...data: T): void;
    /** @override */
    notifyUnsafe(...data: T): void;
    /**
     * Reset the state of the emitter.
     *
     * Further call to {@link Emitter.add} will not automatically resolve,
     * until a new call to {@link Emitter.notify} is performed.
     *
     * @returns Reference to self (for method chaining)
     */
    reset(): this;
    /** Returns the retained data, or `undefined` if no data was retained. */
    get data(): T | undefined;
    /** `true` if data is retained from the last event, `false` otherwise. */
    get isDataRetained(): boolean;
}
export {};
