typegpu
Version:
A thin layer between JS and WebGPU/WGSL that improves development experience and allows for faster iteration.
158 lines (157 loc) • 8.1 kB
TypeScript
import type { TgpuTexture } from '../core/texture/texture.ts';
import type { Disarray, Undecorate } from '../data/dataTypes.ts';
import type { WgslStorageTexture, WgslTexture } from '../data/texture.ts';
import type { U16, U32, WgslArray } from '../data/wgslTypes.ts';
import type { $gpuRepr, $gpuValueOf, $inRepr, $invalidSchemaReason, $memIdent, $repr, $reprPartial, $reprPatch, $validStorageSchema, $validUniformSchema, $validVertexSchema } from './symbols.ts';
import type { ViewDimensionToDimension } from '../core/texture/textureFormats.ts';
import type { Default } from './utilityTypes.ts';
/**
* Extracts the inferred representation of a resource.
* For inferring types as seen by the GPU, see {@link InferGPU}
*
* @example
* type A = Infer<F32> // => number
* type B = Infer<WgslArray<F32>> // => number[]
* type C = Infer<Atomic<U32>> // => number
*/
export type Infer<T> = T extends {
readonly [$repr]: infer TRepr;
} ? TRepr : T;
/**
* Extracts the inferred input (write-side) representation of a resource.
*
* @example
* type A = InferInput<Vec3f> // => v3f | [number, number, number] | Float32Array
* type B = InferInput<WgslArray<Vec3f>> // => (v3f | [number, number, number] | Float32Array)[] | Float32Array
* type C = InferInput<F32> // => number (same as Infer<F32>)
* const arrayOfStructs = d.arrayOf(d.struct({ pos: d.vec3f, id: d.f32 }), 4);
* type D = d.InferInput<typeof arrayOfStructs>; // { pos: d.v3f | Float32Array<ArrayBufferLike> | [number, number, number]; id: number; }[]
*/
export type InferInput<T> = Infer<T> | (T extends {
readonly [$inRepr]: infer TRepr;
} ? TRepr : never);
/**
* Extracts a sparse/partial inferred representation of a resource.
* Used by the `buffer.writePartial` API.
*
* @deprecated
*
* @example
* type A = InferPartial<F32> // => number | undefined
* type B = InferPartial<WgslStruct<{ a: F32 }>> // => { a?: number | undefined }
* type C = InferPartial<WgslArray<F32>> // => { idx: number; value: number | undefined }[] | undefined
*/
export type InferPartial<T> = T extends {
readonly [$reprPartial]: infer TRepr;
} ? TRepr : T extends {
readonly [$repr]: infer TRepr;
} ? TRepr | undefined : T;
/**
* Extracts the inferred representation of a resource (as seen by the GPU).
*
* @example
* type A = InferGPU<F32> // => number
* type B = InferGPU<WgslArray<F32>> // => number[]
* type C = InferGPU<Atomic<U32>> // => atomicU32
*/
export type InferGPU<T> = T extends {
readonly [$gpuRepr]: infer TRepr;
} ? TRepr : Infer<T>;
export type InferRecord<T extends Record<string | number | symbol, unknown>> = {
[Key in keyof T]: Infer<T[Key]>;
};
export type InferInputRecord<T extends Record<string | number | symbol, unknown>> = {
[Key in keyof T]: InferInput<T[Key]>;
};
/** @deprecated */
export type InferPartialRecord<T extends Record<string | number | symbol, unknown>> = {
[Key in keyof T]?: InferPartial<T[Key]>;
};
/**
* Extracts the patch representation of a resource.
* Used by the `buffer.patch` API.
*
* @example
* type A = InferPatch<F32> // => number | undefined
* type B = InferPatch<WgslStruct<{ a: F32 }>> // => { a?: number | undefined }
* type C = InferPatch<WgslArray<F32>> // => Record<number, number | undefined> | number[] | undefined
*/
export type InferPatch<T> = T extends {
readonly [$reprPatch]: infer TRepr;
} ? TRepr : InferInput<T> | undefined;
export type InferPatchRecord<T extends Record<string | number | symbol, unknown>> = {
[Key in keyof T]?: InferPatch<T[Key]>;
};
export type InferGPURecord<T extends Record<string | number | symbol, unknown>> = {
[Key in keyof T]: InferGPU<T[Key]>;
};
export type GPUValueOf<T> = T extends {
readonly [$gpuValueOf]: infer TValue;
} ? TValue : T;
/**
* Expands a schema to a union of other schemas that have the same binary representation.
*
* @example
* type A = MemIdentity<F32> // => F32
* type B = MemIdentity<I32> // => I32 | Atomic<I32> | Decorated<I32, Location[]>
* type C = MemIdentity<WgslArray<I32>> // => WgslArray<I32 | Atomic<I32> | Decorated<I32, Location[]>>
*/
export type MemIdentity<T> = T extends {
readonly [$memIdent]: infer TMemIdent;
} ? TMemIdent : T;
export type MemIdentityRecord<T extends Record<string | number | symbol, unknown>> = {
[Key in keyof T]: MemIdentity<T[Key]>;
};
export type IsValidStorageSchema<T> = (T extends {
readonly [$validStorageSchema]: true;
} ? true : false) extends false ? false : true;
export type IsValidUniformSchema<T> = (T extends {
readonly [$validUniformSchema]: true;
} ? true : false) extends false ? false : true;
export type IsValidVertexSchema<T> = (T extends {
readonly [$validVertexSchema]: true;
} ? true : false) extends false ? false : true;
/**
* Accepts only arrays (or disarrays) of u32 or u16.
*/
export type IsValidIndexSchema<T> = Undecorate<T> extends WgslArray | Disarray ? Undecorate<Undecorate<T>['elementType']> extends U32 | U16 ? true : false : false;
/**
* Checks if a schema can be used in a buffer at all
*/
export type IsValidBufferSchema<T> = IsValidStorageSchema<T> | IsValidUniformSchema<T> | IsValidVertexSchema<T> | IsValidIndexSchema<T> extends false ? false : true;
/**
* Validates if a texture can be used as sampled texture
*/
export type IsValidSampledTextureUsage<TTexture extends TgpuTexture> = TTexture['usableAsSampled'] extends true ? true : {
readonly invalidSampled: "Texture not usable as sampled, call $usage('sampled') first";
};
/**
* Validates if a texture can be used as storage texture
*/
export type IsValidStorageTextureUsage<TTexture extends TgpuTexture> = TTexture['usableAsStorage'] extends true ? true : {
readonly invalidStorage: "Texture not usable as storage, call $usage('storage') first";
};
/**
* Validates if a texture view dimension is compatible with the texture dimension
*/
export type IsValidSubdimension<TTexture extends TgpuTexture, TSchema extends WgslTexture | WgslStorageTexture> = ViewDimensionToDimension[TSchema['dimension']] extends infer TVDim ? TVDim extends Default<TTexture['props']['dimension'], '2d'> ? true : {
readonly invalidViewDim: `Texture dimension '${Default<TTexture['props']['dimension'], '2d'>}' incompatible with view dimension '${TSchema['dimension']}'`;
} : never;
export type IsValidStorageFormat<TTexture extends TgpuTexture, TSchema extends WgslStorageTexture> = TSchema['format'] extends TTexture['props']['format'] ? true : TTexture['props']['viewFormats'] extends readonly unknown[] ? TSchema['format'] extends TTexture['props']['viewFormats'][number] ? true : FormatError<TSchema, TTexture> : FormatError<TSchema, TTexture>;
type FormatError<TSchema extends WgslStorageTexture, TTexture extends TgpuTexture> = {
readonly invalidFormat: `Storage texture format '${TSchema['format']}' incompatible with texture format '${TTexture['props']['format']}'`;
};
type IsExactly<T, U> = [T] extends [U] ? ([U] extends [T] ? true : false) : false;
type SelfOrErrors<TSelf, T> = IsExactly<T, true> extends true ? TSelf : `(Error) ${T[Extract<keyof T, `invalid${string}`>] & string}`;
export type ValidStorageUsage<TTexture extends TgpuTexture, TSchema extends WgslStorageTexture> = IsValidStorageTextureUsage<TTexture> & IsValidSubdimension<TTexture, TSchema> & IsValidStorageFormat<TTexture, TSchema>;
export type ValidSampledUsage<TTexture extends TgpuTexture, TSchema extends WgslTexture> = IsValidSampledTextureUsage<TTexture> & IsValidSubdimension<TTexture, TSchema>;
/**
* Validates texture view schema against texture usage
*/
export type ValidateTextureViewSchema<TTexture extends TgpuTexture, TSchema extends WgslTexture | WgslStorageTexture> = TSchema extends WgslStorageTexture ? SelfOrErrors<TSchema, ValidStorageUsage<TTexture, TSchema>> : TSchema extends WgslTexture ? SelfOrErrors<TSchema, ValidSampledUsage<TTexture, TSchema>> : never;
export type ExtractInvalidSchemaError<T, TPrefix extends string = ''> = [T] extends [
{
readonly [$invalidSchemaReason]: string;
}
] ? `${TPrefix}${T[typeof $invalidSchemaReason]}` : never;
export {};