import type { Block, FuncParameter } from 'tinyest';
import type { IndexFlag, TgpuBuffer, UniformFlag, VertexFlag } from './core/buffer/buffer.ts';
import type { TgpuConst } from './core/constant/tgpuConstant.ts';
import type { TgpuDeclare } from './core/declare/tgpuDeclare.ts';
import type { TgpuComputeFn } from './core/function/tgpuComputeFn.ts';
import type { TgpuFn } from './core/function/tgpuFn.ts';
import type { TgpuFragmentFn } from './core/function/tgpuFragmentFn.ts';
import type { SeparatedEntryArgs } from './core/function/fnTypes.ts';
import type { TgpuVertexFn } from './core/function/tgpuVertexFn.ts';
import type { TgpuComputePipeline } from './core/pipeline/computePipeline.ts';
import type { TgpuRenderPipeline } from './core/pipeline/renderPipeline.ts';
import type { TgpuSampler } from './core/sampler/sampler.ts';
import { type Eventual, type SlotValuePair, type TgpuAccessor, type TgpuLazy, type TgpuSlot } from './core/slot/slotTypes.ts';
import type { TgpuExternalTexture } from './core/texture/externalTexture.ts';
import type { TgpuTexture, TgpuTextureView } from './core/texture/texture.ts';
import type { TgpuVar } from './core/variable/tgpuVariable.ts';
import { type AnyData, UnknownData } from './data/dataTypes.ts';
import type { MapValueToSnippet, ResolvedSnippet, Snippet } from './data/snippet.ts';
import { type AnyMatInstance, type AnyVecInstance, type BaseData } from './data/wgslTypes.ts';
import { $cast, $gpuCallable, $gpuValueOf, $internal, $ownSnippet, $resolve } from './shared/symbols.ts';
import type { TgpuBindGroupLayout, TgpuLayoutEntry } from './tgpuBindGroupLayout.ts';
import type { WgslEnableExtension } from './wgslExtensions.ts';
import type { Infer } from './shared/repr.ts';
import type { ShaderGenerator } from './tgsl/shaderGenerator.ts';
import type { StorageFlag } from './extension.ts';
import type { TgpuBufferBinding } from './core/buffer/bufferBinding.ts';
import type { ShelllessRepository } from './tgsl/shellless.ts';
import type { SupportedLogOp } from './tgsl/consoleLog/types.ts';
export type ResolvableObject = SelfResolvable | TgpuLazy<unknown> | TgpuConst | TgpuDeclare | TgpuBindGroupLayout | TgpuFn | TgpuComputeFn | TgpuFragmentFn | TgpuComputePipeline | TgpuRenderPipeline | TgpuVertexFn | TgpuSampler | TgpuAccessor | TgpuExternalTexture | TgpuTexture | TgpuTextureView | TgpuBufferBinding<BaseData> | TgpuVar | AnyVecInstance | AnyMatInstance | AnyData | ((...args: never[]) => unknown);
export type Wgsl = Eventual<number | boolean | ResolvableObject>;
export type ShaderStage = 'compute' | 'vertex' | 'fragment';
export interface ResolveFunctionOptions {
    functionType: 'normal' | ShaderStage;
    workgroupSize?: readonly number[] | undefined;
    name: string;
    argTypes: BaseData[];
    /**
     * The return type of the function. If undefined, the type should be inferred
     * from the implementation (relevant for shellless functions).
     */
    returnType: BaseData | undefined;
    body: Block;
    params: FuncParameter[];
    externalMap: Record<string, unknown>;
    /**
     * For entry functions: positional args and optional data struct.
     * When provided, takes precedence over `argTypes` for WGSL header generation.
     */
    entryInput?: SeparatedEntryArgs | undefined;
}
export type ItemLayer = {
    type: 'item';
    usedSlots: Set<TgpuSlot<unknown>>;
};
export type FunctionArgumentAccess = () => Snippet | undefined;
export interface FunctionArgument {
    name: string;
    access: FunctionArgumentAccess;
    decoratedType: BaseData;
    used: boolean;
}
export type FunctionScopeLayer = {
    type: 'functionScope';
    functionType: 'normal' | 'compute' | 'vertex' | 'fragment';
    argAccess: Record<string, FunctionArgumentAccess>;
    externalMap: Record<string, unknown>;
    /**
     * The return type of the function. If undefined, the type should be inferred
     * from the implementation (relevant for shellless functions).
     */
    returnType: BaseData | undefined;
    /**
     * All types used in `return` statements.
     */
    reportedReturnTypes: Set<BaseData>;
    /**
     * Maps variables to their modifier placeholders
     */
    placeholderForVariable: Map<Snippet, string>;
    /**
     * Local variables that need `var` modifier.
     */
    modifiedVariables: Set<Snippet>;
};
export type SlotBindingLayer = {
    type: 'slotBinding';
    bindingMap: WeakMap<TgpuSlot<unknown>, unknown>;
};
export type BlockScopeLayer = {
    type: 'blockScope';
    takenLocalIdentifiers: Set<string>;
    declarations: Map<string, Snippet>;
    externals: Map<string, Snippet>;
};
export type StackLayer = ItemLayer | SlotBindingLayer | FunctionScopeLayer | BlockScopeLayer;
export interface ItemStateStack {
    readonly itemDepth: number;
    readonly topItem: ItemLayer;
    readonly topBlockScope: BlockScopeLayer | undefined;
    readonly topFunctionScope: FunctionScopeLayer | undefined;
    pushItem(): void;
    pushSlotBindings(pairs: SlotValuePair[]): void;
    pushFunctionScope(functionType: 'normal' | ShaderStage, argAccess: Record<string, FunctionArgumentAccess>, 
    /**
     * The return type of the function. If undefined, the type should be inferred
     * from the implementation (relevant for shellless functions).
     */
    returnType: BaseData | undefined, externalMap: Record<string, unknown>): FunctionScopeLayer;
    pushBlockScope(): void;
    setBlockExternals(externals: Record<string, Snippet>): void;
    clearBlockExternals(): void;
    pop<T extends StackLayer['type']>(type: T): Extract<StackLayer, {
        type: T;
    }>;
    pop(): StackLayer | undefined;
    readSlot<T>(slot: TgpuSlot<T>): T | undefined;
    getSnippetById(id: string): Snippet | undefined;
    defineBlockVariable(id: string, snippet: Snippet): void;
}
/**
 * # What are execution modes/states? 🤷
 * They're used to control how each TypeGPU resource reacts
 * to actions upon them.
 *
 * ## Normal mode
 * This is the default mode, where resources are acted upon
 * by code either:
 * - Not wrapped inside any of our execution-altering APIs
 * like tgpu.resolve or tgpu.simulate.
 * - Inside tgpu.lazy definitions, where we're taking a break
 *   from codegen/simulation to create resources on-demand.
 *
 * ```ts
 * const count = tgpu.privateVar(d.f32);
 * count.$ += 1; // Illegal in top-level
 *
 * const root = await tgpu.init();
 * const countMutable = root.createMutable(d.f32);
 * countMutable.$ = [1, 2, 3]; // Illegal in top-level
 * countMutable.write([1, 2, 3]); // OK!
 * ```
 *
 * ## Codegen mode
 * Brought upon by `tgpu.resolve()` (or higher-level APIs using it like our pipelines).
 * Resources are expected to generate WGSL code that represents them, instead of
 * fulfilling their task in JS.
 *
 * ```ts
 * const foo = tgpu.fn([], d.f32)(() => 123);
 * // The following is running in `codegen` mode
 * console.log(foo()); // Prints `foo_0()`
 * ```
 *
 * ## Simulate mode
 * Callbacks passed to `tgpu.simulate()` are executed in this mode. Each 'simulation'
 * is isolated, and does not share state with other simulations (even nested ones).
 * Variables and buffers can be accessed and mutated directly, and their state
 * is returned at the end of the simulation.
 *
 * ```ts
 * const var = tgpu.privateVar(d.f32, 0);
 *
 * const result = tgpu.simulate(() => {
 *   // This is running in `simulate` mode
 *   var.$ += 1; // Direct access is legal
 *   return var.$; // Returns 1
 * });
 *
 * console.log(result.value); // Prints 1
 * ```
 */
export type ExecMode = 'normal' | 'codegen' | 'simulate';
export declare class NormalState {
    readonly type: "normal";
}
export declare class CodegenState {
    readonly type: "codegen";
}
export declare class SimulationState {
    readonly type: "simulate";
    readonly buffers: Map<TgpuBuffer<BaseData>, unknown>;
    readonly vars: {
        private: Map<TgpuVar, unknown>;
        workgroup: Map<TgpuVar, unknown>;
    };
    constructor(buffers: Map<TgpuBuffer<BaseData>, unknown>, vars: {
        private: Map<TgpuVar, unknown>;
        workgroup: Map<TgpuVar, unknown>;
    });
}
export type ExecState = NormalState | CodegenState | SimulationState;
/**
 * Passed into each resolvable item. All items in a tree share a resolution ctx,
 * but there can be layers added and removed from the item stack when going down
 * and up the tree.
 */
export interface ResolutionCtx {
    [$internal]: {
        itemStateStack: ItemStateStack;
    };
    readonly pre: string;
    readonly mode: ExecState;
    readonly enableExtensions: WgslEnableExtension[] | undefined;
    readonly gen: ShaderGenerator;
    /**
     * Used by `typedExpression` to signal downstream
     * expression resolution what type is expected of them.
     *
     * It is used exclusively for inferring the types of structs and arrays.
     * It is modified exclusively by `typedExpression` function.
     */
    expectedType: (BaseData | BaseData[]) | undefined;
    readonly topFunctionScope: FunctionScopeLayer | undefined;
    readonly topFunctionReturnType: BaseData | undefined;
    readonly blockDepth: number;
    readonly shelllessRepo: ShelllessRepository;
    /**
     * Adds a module-scope declaration to the resolution output.
     * @param declaration - The WGSL code of the declaration.
     * @param name - The identifier the declaration declares (a fn, struct, var,
     *   const or alias name), if it declares one. Reported back to the caller
     *   through `ResolutionResult.declarations`.
     */
    addDeclaration(declaration: string, name?: string): void;
    withResetIndentLevel<T>(callback: () => T): T;
    /**
     * Reserves a bind group number, and returns a placeholder that will be replaced
     * with a concrete number at the end of the resolution process.
     */
    allocateLayoutEntry(layout: TgpuBindGroupLayout): string;
    /**
     * Reserves a spot in the catch-all bind group, without the indirection of a bind-group.
     * This means the resource is 'fixed', and cannot be swapped between code execution.
     */
    allocateFixedEntry(layoutEntry: TgpuLayoutEntry, resource: object): {
        group: string;
        binding: number;
    };
    withSlots<T>(pairs: SlotValuePair[], callback: () => T): T;
    pushMode(state: ExecState): void;
    popMode(expected?: ExecMode): void;
    /**
     * Unwraps all layers of slot/lazy indirection and returns the concrete value if available.
     * @throws {MissingSlotValueError}
     */
    unwrap<T>(eventual: Eventual<T>): T;
    /**
     * Returns the snippet representing `item`.
     *
     * @param item The value to resolve
     * @param schema Additional information about the item's data type
     */
    resolve(item: unknown, schema?: BaseData | UnknownData): ResolvedSnippet;
    /**
     * Equivalent to `snip(ctx.resolve(snippet.value, snippet.dataType).value, snippet.dataType, snippet.origin, snippet.possibleSideEffects)`.
     */
    resolveSnippet(snippet: Snippet): ResolvedSnippet;
    resolveFunction(options: ResolveFunctionOptions): {
        code: string;
        returnType: BaseData;
    };
    withVaryingLocations<T>(locations: Record<string, number>, callback: () => T): T;
    get varyingLocations(): Record<string, number> | undefined;
    /**
     * Temporarily renames the item.
     * Useful for resolutions with slots,
     * since functions with different slots should have different names,
     * and all hold the same inner function that is being resolved multiple times.
     * @param item the item to rename
     * @param name the temporary name to assign to the item (if missing, just returns `callback()`)
     */
    withRenamed<T>(item: object, name: string | undefined, callback: () => T): T;
    /**
     * @param primer The basis for the unique identifier. Depending on the strategy, or
     *               the names already taken, this may be modified to ensure uniqueness.
     * @param scope The scope in which to generate the identifier. 'global' means
     *              the identifier is meant to be unique across the entire program, while
     *              'block' means it cannot shadow any existing identifiers visible from
     *              within the current block. After the block is popped, any identifiers
     *              defined within it are no longer visible.
     * @returns an identifier that is unique within the given scope
     */
    makeUniqueIdentifier(primer: string | undefined, scope: 'global' | 'block'): string;
    isIdentifierBanned(name: string): boolean;
    /**
     * @param name The name to check.
     * @param scope The scope in which we want to place the identifier.
     */
    isIdentifierTaken(name: string, scope: 'global' | 'block'): boolean;
    /**
     * Makes sure the given identifier cannot be generated by {@link makeUniqueIdentifier}
     * within the given scope.
     * @param name The name to reserve
     * @param scope See {@link makeUniqueIdentifier} for a description of the scope parameter.
     */
    reserveIdentifier(name: string, scope: 'global' | 'block'): void;
    indent(): string;
    dedent(): string;
    /**
     * Returns a version of `code` with one level of indentation less.
     *
     * @note If a line has no indentation, it will be kept as is, which
     * can cause some lines to dedent and some to be left as they are.
     */
    getDedented(code: string): string;
    pushBlockScope(): void;
    popBlockScope(): void;
    generateLog(op: SupportedLogOp, args: Snippet[]): Snippet;
    getById(id: string): Snippet | null;
    defineVariable(id: string, snippet: Snippet): void;
    setBlockExternals(externals: Record<string, Snippet>): void;
    clearBlockExternals(): void;
    /**
     * Types that are used in `return` statements are
     * reported using this function, and used to infer
     * the return type of the owning function.
     */
    reportReturnType(dataType: BaseData): void;
}
/**
 * Houses a method on the symbol '$resolve` that returns a
 * code string representing it, as opposed to offloading the
 * resolution to another mechanism.
 */
export interface SelfResolvable {
    [$internal]: unknown;
    [$resolve](ctx: ResolutionCtx): ResolvedSnippet;
    toString(): string;
}
export declare function isSelfResolvable(value: unknown): value is SelfResolvable;
export interface WithGPUValue<T> {
    readonly [$gpuValueOf]: T;
}
export interface WithOwnSnippet {
    readonly [$ownSnippet]: Snippet;
}
export declare function getOwnSnippet(value: unknown): Snippet | undefined;
export interface GPUCallable<TArgs extends unknown[] = unknown[]> {
    [$gpuCallable]: {
        strictSignature?: {
            argTypes: (BaseData | BaseData[])[];
            returnType: BaseData;
        } | undefined;
        call(ctx: ResolutionCtx, args: MapValueToSnippet<TArgs>): Snippet;
    };
}
export declare function isGPUCallable(value: unknown): value is GPUCallable;
export type WithCast<T = BaseData> = GPUCallable<[v?: Infer<T>]> & {
    readonly [$cast]: (v?: Infer<T>) => Infer<T>;
};
export declare function hasCast(value: unknown): value is WithCast;
type AnyFn = (...args: never[]) => unknown;
export type DualFn<T extends AnyFn> = T & GPUCallable<Parameters<T>>;
export declare function isKnownAtComptime(snippet: Snippet): boolean;
export declare function isWgsl(value: unknown): value is Wgsl;
export type BindableBufferUsage = 'uniform' | 'readonly' | 'mutable';
export type BufferUsage = 'uniform' | 'readonly' | 'mutable' | 'vertex';
export declare function isGPUBuffer(value: unknown): value is GPUBuffer;
export declare function isBuffer(value: unknown): value is TgpuBuffer<BaseData>;
export declare function isUsableAsVertex<T extends TgpuBuffer<BaseData>>(buffer: T): buffer is T & VertexFlag;
export declare function isUsableAsIndex<T extends TgpuBuffer<BaseData>>(buffer: T): buffer is T & IndexFlag;
export declare function isUsableAsUniform<T extends TgpuBuffer<BaseData>>(buffer: T): buffer is T & UniformFlag;
export declare function isUsableAsStorage<T>(value: T): value is T & StorageFlag;
export {};
