import type { Bucket } from "../bucket.js";
import type { Step } from "../step";
import type { __ValueStep } from "../steps/index.js";
import type { OperationPlan } from "./OperationPlan";
/** Non-branching, non-deferred */
export interface LayerPlanReasonRoot {
    type: "root";
}
/** Non-branching, non-deferred */
export interface LayerPlanReasonNullableField {
    type: "nullableBoundary";
    parentLayerPlan: LayerPlan;
    /**
     * Can be used such that the same LayerPlan can be used for two selection
     * sets for the same parent plan. In this case an additional output plan
     * would be added to the LayerPlan.
     *
     * Also needed for execution (see `executeBucket`).
     */
    parentStep: Step;
}
export interface LayerPlanReasonListItemStream {
    initialCountStepId?: number;
    ifStepId?: number;
    labelStepId?: number;
}
/** Non-branching, non-deferred */
export interface LayerPlanReasonListItem {
    type: "listItem";
    parentLayerPlan: LayerPlan;
    /**
     * Can be used such that the same LayerPlan can be used for two lists for
     * the same parent plan. In this case an additional output plan would be
     * added to the LayerPlan.
     *
     * Also needed for execution (see `executeBucket`).
     */
    parentStep: Step;
    /**
     * If this listItem is to be streamed, the configuration for that streaming.
     */
    stream?: LayerPlanReasonListItemStream;
}
/** Non-branching, deferred */
export interface LayerPlanReasonSubscription {
    type: "subscription";
    parentLayerPlan: LayerPlan;
}
/** Non-branching, deferred */
export interface LayerPlanReasonMutationField {
    type: "mutationField";
    parentLayerPlan: LayerPlan;
    mutationIndex: number;
}
/** Non-branching, deferred */
export interface LayerPlanReasonDefer {
    type: "defer";
    parentLayerPlan: LayerPlan;
    label?: string;
}
/**
 * Non-branching, non-deferred
 *
 * A polymorphic bucket indicates a transition between values of unknown type
 * and values of a known polymorphic type. This is predicated based on the
 * given typename - before the typename is known, we must run all steps for all
 * types, but once the type is known we can be more selective about which steps
 * to run.
 *
 * When a polymorphic type is met, there will always be a polymorphic layer
 * plan, even if all steps within it run for all types. This is necessary to
 * advance the `polymorphicPathList` index for the relevant indicies.
 */
export interface LayerPlanReasonPolymorphic {
    type: "polymorphic";
    parentLayerPlan: LayerPlan;
    typeNames: string[];
    /**
     * Stores the __typename, needed for execution (see `executeBucket`).
     */
    parentStep: Step<string | null>;
    polymorphicPaths: Set<string>;
}
/**
 * Branching, non-deferred
 *
 * A polymorphicPartition bucket accepts a subset of types and contains only
 * steps relevant to those types; it's a way to avoid having to do a lot of
 * filtering of values being passed into steps' execute methods by
 * pre-filtering the values.
 */
export interface LayerPlanReasonPolymorphicPartition {
    type: "polymorphicPartition";
    parentLayerPlan: LayerPlan<LayerPlanReasonPolymorphic>;
    typeNames: string[];
    polymorphicPaths: ReadonlySet<string>;
}
/** Non-branching, non-deferred */
export interface LayerPlanReasonSubroutine {
    type: "subroutine";
    parentLayerPlan: LayerPlan;
    parentStep: Step;
}
/**
 * Anti-branching, non-deferred
 *
 * A "combined" layer plan exists to re-combine values from multiple layer
 * plans together again, to allow future steps to be more efficient. It's
 * typically relevant when polymorphism has occurred and has caused branching,
 * the combined layer plan allows the values to be recombined before branching
 * again, such that L layers of polymorphism, where there are P different
 * polymorphic branches at each layer, results in P*L branches rather than P^L
 * branches - i.e. it scales linary with number of layers rather than
 * exponentially.
 */
export interface LayerPlanReasonCombined {
    type: "combined";
    parentLayerPlans: ReadonlyArray<LayerPlan>;
}
export declare function hasParentLayerPlan(reason: LayerPlanReason): reason is Exclude<LayerPlanReason, LayerPlanReasonRoot | LayerPlanReasonCombined>;
export declare function isDeferredLayerPlan(layerPlan: LayerPlan): boolean;
export type LayerPlanReason = LayerPlanReasonRoot | LayerPlanReasonNullableField | LayerPlanReasonListItem | LayerPlanReasonSubscription | LayerPlanReasonMutationField | LayerPlanReasonDefer | LayerPlanReasonPolymorphic | LayerPlanReasonPolymorphicPartition | LayerPlanReasonCombined | LayerPlanReasonSubroutine;
export type HasParent<A extends LayerPlanReason> = A extends any ? A extends {
    parentStep: Step;
} ? A : never : never;
export type LayerPlanReasonsWithParentStep = HasParent<LayerPlanReason>;
/**
 * A LayerPlan represents (via "reason") either the root (root), when something
 * happens at a later time (mutationField, defer), when plurality changes
 * (list, stream, subscription, polymorphic), or when a subprocess needs to be
 * computed (subroutine).
 *
 * Layer plans belong to an operation plan.
 *
 * Every layer plan (except for the root layer plan) has exactly one parent
 * layer plan.
 *
 * Every layer plan is caused by a parent step.
 *
 * The LayerPlan of a step influences:
 *
 * 1. how steps are deduplicated
 * 2. the order in which the steps are executed
 * 3. where the result of executing the step is stored
 * 4. when the step execution cache is allowed to be GC'd
 *
 * NOTE: `__ListTransformStep`'s effectively have a temporary bucket inside
 * them (built on the `__Item`) that's thrown away once the transform is
 * complete.
 *
 */
export declare class LayerPlan<TReason extends LayerPlanReason = LayerPlanReason> {
    readonly operationPlan: OperationPlan;
    readonly reason: TReason;
    id: number;
    /** How "deep" this layer plan is (how many ancestors it has). The root layer plan has a depth of 0. */
    depth: number;
    /** The depth at which a "defer boundary" occurs (OperationPlan.getPeers cannot pass a defer boundary), or 0. */
    deferBoundaryDepth: number;
    /**
     * An optimization for OperationPlan.getPeers; this tracks the steps in this
     * layer plan, grouped by their step class.
     */
    stepsByConstructor: Map<Function, Set<Step>>;
    /**
     * Populated during `finalize`, this will be empty except for phase
     * transition layer plans (defer/stream) wherein it will contain a list of
     * "unreachable" layer plan IDs relevant to the "combined" layer plans trying
     * to refer to parent layer plans which are outside of this incremental
     * boundary (e.g. if two lists both stream, we might combine those, but at
     * runtime only one will be populated so we can't wait for the other to
     * complete otherwise nothing will happen).
     */
    outOfBoundsLayerPlanIds: Set<number>;
    constructor(operationPlan: OperationPlan, reason: TReason);
    toString(): string;
    print(depth?: number): string;
    _hasSetRootStep: boolean;
    setRootStep($root: Step): void;
    finalize(): void;
    newBucket(parentBucket: Bucket): Bucket | null;
    newCombinedBucket(finalParentBucket: Pick<Bucket, "sharedState">): Bucket | null;
    addCombo(sources: ReadonlyArray<{
        layerPlan: LayerPlan;
        step: Step;
    }>, $target: __ValueStep<any>): void;
}
//# sourceMappingURL=LayerPlan.d.ts.map