import { ReadonlyCircularQueue } from 'reactive-circular-queue';
import { ReadonlyStore } from 'universal-stores';
export type { ReadonlyCircularQueue } from 'reactive-circular-queue';
export { NotEnoughAvailableSlotsQueueError, NotEnoughFilledSlotsQueueError, } from 'reactive-circular-queue';
export type { Unsubscribe, Subscriber, ReadonlyStore } from 'universal-stores';
/**
 * Error that occurs when the channel buffer has been filled up, and thus it cannot
 * accept any more `send` calls.
 */
export declare class ChannelFullError extends Error {
    constructor();
}
/**
 * Error that occurs trying to send or receive data from
 * a closed channel.
 */
export declare class ChannelClosedError extends Error {
    constructor();
}
/**
 * Error that occurs when calling `recv`
 * and there are already too many enqueued similar requests.
 */
export declare class ChannelTooManyPendingRecvError extends Error {
    constructor();
}
/**
 * Transmission end of a channel.
 */
export type ChannelTx<T> = {
    /**
     * Push data into the channel.
     * This operation enqueues the passed value in the transmission queue if there
     * is no pending `recv`.
     * @param v the data to send.
     * @throws {ChannelClosedError} if the channel is closed.
     * @throws {ChannelFullError} if the channel is transmission queue is full.
     */
    send(v: T): void;
    /**
     * Push data into the channel and waits for it to be consumed by the receiving end.
     * This operation enqueues the passed value in the transmission queue if there
     * is no pending `recv`, but removes it if the operation is aborted by an abort
     * signal.
     * @param v the data to send.
     * @param options.signal (optional) an abort signal to stop the pending promise.
     * If this signal emits before `sendWait` can resolve, the enqueued value will be removed
     * and the emitted value will be "thrown" (as in `throw ...;`) to the caller
     * of `sendWait`.
     * @throws {ChannelClosedError} if the channel is closed.
     * @throws {ChannelFullError} if the channel is transmission queue is full.
     * @throws {unknown} if `signal` triggers before `sendWait` can resolve.
     */
    sendWait(v: T, options?: {
        signal?: AbortSignal;
    }): Promise<void>;
    /**
     * A store that contains true if the transmission buffer is not full and the channel is not closed.
     */
    canWrite$: ReadonlyStore<boolean>;
    /**
     * A store that contains the number of available slots (from 0 to the channel capacity) in the output buffer or 0 if the channel is closed.
     */
    availableOutboxSlots$: ReadonlyStore<number>;
    /**
     * Return the total size (number of slots) of the channel buffer.
     */
    get capacity(): number;
    /**
     * Close the channel, stopping all pending send/recv requests.
     */
    close(): void;
    /**
     * A store that contains true if the channel is closed.
     */
    closed$: ReadonlyStore<boolean>;
};
/**
 * Receiving end of a channel.
 */
export type ChannelRx<T> = {
    /**
     * A store that contains true if there is some data ready to be consumed, the channel is not closed and there are not too many pending `recv` requests.
     */
    canRead$: ReadonlyStore<boolean>;
    /**
     * A store that contains the number of filled slots (from 0 to the channel capacity) in the input buffer or 0 if the channel is closed.
     */
    filledInboxSlots$: ReadonlyStore<number>;
    /**
     * Return the total size (number of slots) of the channel buffer.
     */
    get capacity(): number;
    /**
     * Consume data from the channel buffer.
     * If there is no data in the channel, this method will block the caller
     * until it's available.
     * @param options.signal (optional) an abort signal to stop the pending promise.
     * If this signal triggers before `recv` can resolve, the channel buffer won't be
     * consumed and the abort reason value will be "thrown" (as in `throw ...;`) to the caller
     * of `recv`.
     * @throws {ChannelClosedError} if the channel is closed.
     * @throws {unknown} if `.abort(...)` is called before `recv` is able to consume the channel buffer.
     */
    recv(options?: {
        signal?: AbortSignal;
    }): Promise<T>;
    /**
     * Return an async iterator that consumes the channel buffer
     * If the channel buffer is already empty the iterator will not emit any value.
     */
    iter(): AsyncIterator<T>;
    /**
     * Return an async iterator that consumes the channel buffer
     * If the channel buffer is already empty the iterator will not emit any value.
     */
    [Symbol.asyncIterator](): AsyncIterator<T>;
    /**
     * Close the channel, stopping all pending send/recv requests.
     */
    close(): void;
    /**
     * A store that contains true if the channel is closed.
     */
    closed$: ReadonlyStore<boolean>;
    /**
     * A store that contains the number of currently waiting `recv` promises.
     */
    pendingRecvPromises$: ReadonlyStore<number>;
};
/**
 * A Channel is an abstraction that enables
 * communication between asynchronous tasks.
 * A channel exposes two objects: `tx` and `rx`,
 * which respectively provide methods to transmit
 * and receive data.
 *
 * Channels can be used and combined in a multitude of
 * ways. The simplest way to use a channel is by creating
 * a simplex communication: one task transmit data, another consumes it.
 * A full-duplex communication can be achieved by creating two channels
 * and exchanging the `rx` and `tx` objects between two tasks.
 *
 * It's also possible to create a Multiple Producers Single Consumer (mpsc) scenario
 * by sharing a single channel among several tasks.
 */
export type Channel<T> = {
    /**
     * Transmission end of the channel.
     */
    tx: ChannelTx<T>;
    /**
     * Receiving end of the channel.
     */
    rx: ChannelRx<T>;
    /**
     * Return the internal buffer in readonly mode.
     */
    get buffer(): ReadonlyCircularQueue<T>;
};
export type MakeChannelParams = {
    /** (optional, defaults to 1024) The maximum number of items that the channel can buffer while waiting data to be consumed. */
    capacity?: number;
    /** (optional, defaults to 1024) The maximum number of pending `recv`. If this limit is reached, `recv` will immediately reject with {@link ChannelTooManyPendingRecvError}. */
    maxConcurrentPendingRecv?: number;
};
/**
 * Create a Channel.
 *
 * A Channel is an abstraction that enables
 * communication between asynchronous tasks.
 * A channel exposes two objects: `tx` and `rx`,
 * which respectively provide methods to transmit
 * and receive data.
 *
 * Channels can be used and combined in a multitude of
 * ways. The simplest way to use a channel is by creating
 * a simplex communication: one task transmit data, another consumes it.
 * A full-duplex communication can be achieved by creating two channels
 * and exchanging the `rx` and `tx` objects between two tasks.
 *
 * It's also possible to create a Multiple Producers Single Consumer (mpsc) scenario
 * by sharing a single channel among several tasks.
 *
 * Example:
 * ```ts
 * const {tx, rx} = makeChannel<number>();
 * rx.recv().then((n) => console.log('Here it is: ' + n)); // doesn't print anything, the channel is currently empty.
 * tx.send(1); // resolves the above promise, causing it to print 'Here it is: 1'
 * ```
 *
 * @param params (optional) configuration parameters for this channel (e.g maximum capacity).
 * @param params.capacity (optional, defaults to 1024) The maximum number of items that the channel can buffer while waiting data to be consumed.
 * @param params.maxConcurrentPendingRecv (optional, defaults to 1024) The maximum number of pending `recv`. If this limit is reached, `recv` will immediately reject with {@link ChannelTooManyPendingRecvError}.
 * @returns a {@link Channel}
 */
export declare function makeChannel<T>(params?: MakeChannelParams): Channel<T>;
