diff --git a/packages/typegpu/src/core/buffer/buffer.ts b/packages/typegpu/src/core/buffer/buffer.ts index b8b16e204d..582dc8f284 100644 --- a/packages/typegpu/src/core/buffer/buffer.ts +++ b/packages/typegpu/src/core/buffer/buffer.ts @@ -9,16 +9,14 @@ import { isWgslData } from '../../data/wgslTypes.ts'; import type { StorageFlag } from '../../extension.ts'; import type { TgpuNamable } from '../../shared/meta.ts'; import { getName, setName } from '../../shared/meta.ts'; -import type { - Infer, - InferPartial, - IsValidIndexSchema, - IsValidStorageSchema, - IsValidUniformSchema, - IsValidVertexSchema, - MemIdentity, -} from '../../shared/repr.ts'; -import { $internal } from '../../shared/symbols.ts'; +import type { Infer, InferPartial, MemIdentity } from '../../shared/repr.ts'; +import { + $internal, + type $invalidIndexSchema, + type $invalidStorageSchema, + type $invalidUniformSchema, + type $invalidVertexSchema, +} from '../../shared/symbols.ts'; import type { Prettify, UnionToIntersection, @@ -84,15 +82,17 @@ const usageToUsageConstructor = { uniform, mutable, readonly }; /** * Done as an object to later Prettify it */ -type InnerValidUsagesFor = { +type InnerValidUsagesFor = { usage: - | (IsValidStorageSchema extends true ? 'storage' : never) - | (IsValidUniformSchema extends true ? 'uniform' : never) - | (IsValidVertexSchema extends true ? 'vertex' : never) - | (IsValidIndexSchema extends true ? 'index' : never); + | (T[typeof $invalidStorageSchema] extends string ? never : 'storage') + | (T[typeof $invalidUniformSchema] extends string ? never : 'uniform') + | (T[typeof $invalidVertexSchema] extends string ? never : 'vertex') + | (T[typeof $invalidIndexSchema] extends string ? never : 'index'); }; -export type ValidUsagesFor = InnerValidUsagesFor['usage']; +export type ValidUsagesFor = InnerValidUsagesFor< + T +>['usage']; export interface TgpuBuffer extends TgpuNamable { readonly [$internal]: true; diff --git a/packages/typegpu/src/core/root/rootTypes.ts b/packages/typegpu/src/core/root/rootTypes.ts index 9cf0986dd4..5759261e98 100644 --- a/packages/typegpu/src/core/root/rootTypes.ts +++ b/packages/typegpu/src/core/root/rootTypes.ts @@ -10,7 +10,6 @@ import type { WgslSamplerProps, } from '../../data/sampler.ts'; import type { - AnyWgslData, BaseData, U16, U32, @@ -19,15 +18,14 @@ import type { Void, WgslArray, } from '../../data/wgslTypes.ts'; -import type { - ExtractInvalidSchemaError, - Infer, - InferGPURecord, - IsValidBufferSchema, - IsValidStorageSchema, - IsValidUniformSchema, -} from '../../shared/repr.ts'; -import { $internal } from '../../shared/symbols.ts'; +import type { ExtractInvalidSchemaError, Infer } from '../../shared/repr.ts'; +import { + $internal, + $invalidIndexSchema, + $invalidStorageSchema, + $invalidUniformSchema, + $invalidVertexSchema, +} from '../../shared/symbols.ts'; import type { Assume, Mutable, @@ -80,6 +78,7 @@ import type { import type { TgpuVertexLayout } from '../vertexLayout/vertexLayout.ts'; import type { TgpuComputeFn } from './../function/tgpuComputeFn.ts'; import type { TgpuNamable } from '../../shared/meta.ts'; +import { Illegal } from '../../errors.ts'; import type { AnyAutoCustoms, AutoFragmentIn, @@ -751,20 +750,21 @@ export interface RenderPass { ): undefined; } -export type ValidateBufferSchema = - IsValidBufferSchema extends false - ? ExtractInvalidSchemaError - : TData; - -export type ValidateStorageSchema = - IsValidStorageSchema extends false - ? ExtractInvalidSchemaError - : TData; - -export type ValidateUniformSchema = - IsValidUniformSchema extends false - ? ExtractInvalidSchemaError - : TData; +/** @deprecated Not useful anymore, it's now an identity type */ +export type ValidateBufferSchema = TData; +/** @deprecated Not useful anymore, it's now an identity type */ +export type ValidateStorageSchema = TData; +/** @deprecated Not useful anymore, it's now an identity type */ +export type ValidateUniformSchema = TData; + +type InvalidBufferData = + & BaseData + & ({ + readonly [$invalidStorageSchema]: string; + readonly [$invalidUniformSchema]: string; + readonly [$invalidVertexSchema]: string; + readonly [$invalidIndexSchema]: string; + }); export type ConfigureContextOptions = { /** @@ -795,6 +795,16 @@ export interface TgpuRoot extends Unwrapper { */ configureContext(options: ConfigureContextOptions): GPUCanvasContext; + /** + * **The provided schema is not host-shareable** + * @deprecated + */ + createBuffer( + typeSchema: TData, + // NoInfer is there to infer the schema type just based on the first parameter + initial?: Infer> | undefined, + ): Illegal>; + /** * Allocates memory on the GPU, allows passing data between host and shader. * @@ -804,8 +814,8 @@ export interface TgpuRoot extends Unwrapper { * @param typeSchema The type of data that this buffer will hold. * @param initial The initial value of the buffer. (optional) */ - createBuffer( - typeSchema: ValidateBufferSchema, + createBuffer( + typeSchema: TData, // NoInfer is there to infer the schema type just based on the first parameter initial?: Infer> | undefined, ): TgpuBuffer; @@ -819,7 +829,7 @@ export interface TgpuRoot extends Unwrapper { * @param typeSchema The type of data that this buffer will hold. * @param gpuBuffer A vanilla WebGPU buffer. */ - createBuffer( + createBuffer( typeSchema: ValidateBufferSchema, gpuBuffer: GPUBuffer, ): TgpuBuffer; @@ -832,7 +842,7 @@ export interface TgpuRoot extends Unwrapper { * @param typeSchema The type of data that this buffer will hold. * @param initial The initial value of the buffer. (optional) */ - createUniform( + createUniform( typeSchema: ValidateUniformSchema, // NoInfer is there to infer the schema type just based on the first parameter initial?: Infer>, @@ -846,7 +856,7 @@ export interface TgpuRoot extends Unwrapper { * @param typeSchema The type of data that this buffer will hold. * @param gpuBuffer A vanilla WebGPU buffer. */ - createUniform( + createUniform( typeSchema: ValidateUniformSchema, gpuBuffer: GPUBuffer, ): TgpuUniform; @@ -859,7 +869,7 @@ export interface TgpuRoot extends Unwrapper { * @param typeSchema The type of data that this buffer will hold. * @param initial The initial value of the buffer. (optional) */ - createMutable( + createMutable( typeSchema: ValidateStorageSchema, // NoInfer is there to infer the schema type just based on the first parameter initial?: Infer>, @@ -873,7 +883,7 @@ export interface TgpuRoot extends Unwrapper { * @param typeSchema The type of data that this buffer will hold. * @param gpuBuffer A vanilla WebGPU buffer. */ - createMutable( + createMutable( typeSchema: ValidateStorageSchema, gpuBuffer: GPUBuffer, ): TgpuMutable; @@ -886,7 +896,7 @@ export interface TgpuRoot extends Unwrapper { * @param typeSchema The type of data that this buffer will hold. * @param initial The initial value of the buffer. (optional) */ - createReadonly( + createReadonly( typeSchema: ValidateStorageSchema, // NoInfer is there to infer the schema type just based on the first parameter initial?: Infer>, @@ -900,7 +910,7 @@ export interface TgpuRoot extends Unwrapper { * @param typeSchema The type of data that this buffer will hold. * @param gpuBuffer A vanilla WebGPU buffer. */ - createReadonly( + createReadonly( typeSchema: ValidateStorageSchema, gpuBuffer: GPUBuffer, ): TgpuReadonly; diff --git a/packages/typegpu/src/data/atomic.ts b/packages/typegpu/src/data/atomic.ts index 7101ac8901..4c107d3693 100644 --- a/packages/typegpu/src/data/atomic.ts +++ b/packages/typegpu/src/data/atomic.ts @@ -1,5 +1,5 @@ import type { Infer, MemIdentity } from '../shared/repr.ts'; -import { $internal } from '../shared/symbols.ts'; +import { $internal, $validIndexSchema } from '../shared/symbols.ts'; import { $gpuRepr, $memIdent, @@ -36,15 +36,21 @@ export function atomic( class AtomicImpl implements Atomic { public readonly [$internal] = {}; public readonly type = 'atomic'; + public readonly [$validStorageSchema]: true; + public readonly [$validUniformSchema]: true; + public readonly [$validVertexSchema]: true; + public readonly [$validIndexSchema]: false; // Type-tokens, not available at runtime declare readonly [$repr]: Infer; declare readonly [$memIdent]: MemIdentity; declare readonly [$gpuRepr]: TSchema extends U32 ? atomicU32 : atomicI32; - declare readonly [$validStorageSchema]: true; - declare readonly [$validUniformSchema]: true; - declare readonly [$validVertexSchema]: true; // --- - constructor(public readonly inner: TSchema) {} + constructor(public readonly inner: TSchema) { + this[$validStorageSchema] = true; + this[$validUniformSchema] = true; + this[$validVertexSchema] = true; + this[$validIndexSchema] = false; + } } diff --git a/packages/typegpu/src/data/attributes.ts b/packages/typegpu/src/data/attributes.ts index d2a0d0167c..0a97fb41f7 100644 --- a/packages/typegpu/src/data/attributes.ts +++ b/packages/typegpu/src/data/attributes.ts @@ -2,18 +2,16 @@ import type { Infer, InferGPU, InferPartial, - IsValidStorageSchema, - IsValidUniformSchema, - IsValidVertexSchema, MemIdentity, } from '../shared/repr.ts'; -import { $internal } from '../shared/symbols.ts'; import { $gpuRepr, + $internal, $invalidSchemaReason, $memIdent, $repr, $reprPartial, + $validIndexSchema, $validStorageSchema, $validUniformSchema, $validVertexSchema, @@ -360,6 +358,11 @@ export function getAttributesString(field: T): string { class BaseDecoratedImpl { public readonly [$internal] = {}; + public readonly [$validStorageSchema]: boolean; + public readonly [$validUniformSchema]: boolean; + public readonly [$validVertexSchema]: boolean; + public readonly [$validIndexSchema]: boolean; + public [$invalidSchemaReason]?: string | undefined; // Type-tokens, not available at runtime declare readonly [$repr]: Infer; @@ -371,6 +374,12 @@ class BaseDecoratedImpl { public readonly inner: TInner, public readonly attribs: TAttribs, ) { + this[$validStorageSchema] = inner[$validStorageSchema]; + this[$validUniformSchema] = inner[$validUniformSchema]; + this[$validVertexSchema] = inner[$validVertexSchema]; + this[$validIndexSchema] = inner[$validIndexSchema]; + this[$invalidSchemaReason] = inner[$invalidSchemaReason]; + const alignAttrib = attribs.find(isAlignAttrib)?.params[0]; const sizeAttrib = attribs.find(isSizeAttrib)?.params[0]; @@ -421,16 +430,15 @@ class DecoratedImpl implements Decorated { public readonly [$internal] = {}; public readonly type = 'decorated'; + declare readonly [$validStorageSchema]: TInner[typeof $validStorageSchema]; + declare readonly [$validUniformSchema]: TInner[typeof $validUniformSchema]; + declare readonly [$validVertexSchema]: TInner[typeof $validVertexSchema]; + declare readonly [$validIndexSchema]: false; // Type-tokens, not available at runtime declare readonly [$memIdent]: TAttribs extends Location[] ? MemIdentity | Decorated, TAttribs> : Decorated, TAttribs>; - declare readonly [$invalidSchemaReason]: - Decorated[typeof $invalidSchemaReason]; - declare readonly [$validStorageSchema]: IsValidStorageSchema; - declare readonly [$validUniformSchema]: IsValidUniformSchema; - declare readonly [$validVertexSchema]: IsValidVertexSchema; // --- } @@ -439,10 +447,17 @@ class LooseDecoratedImpl implements LooseDecorated { public readonly [$internal] = {}; public readonly type = 'loose-decorated'; + declare readonly [$validStorageSchema]: false; + declare readonly [$validUniformSchema]: false; + declare readonly [$validVertexSchema]: TInner[typeof $validVertexSchema]; + declare readonly [$validIndexSchema]: false; - // Type-tokens, not available at runtime - declare readonly [$invalidSchemaReason]: - LooseDecorated[typeof $invalidSchemaReason]; - declare readonly [$validVertexSchema]: IsValidVertexSchema; - // --- + constructor( + public readonly inner: TInner, + public readonly attribs: TAttribs, + ) { + super(inner, attribs); + this[$invalidSchemaReason] = + 'Loosely decorated schemas are not host-shareable'; + } } diff --git a/packages/typegpu/src/data/dataTypes.ts b/packages/typegpu/src/data/dataTypes.ts index d2394b297c..8da94d3757 100644 --- a/packages/typegpu/src/data/dataTypes.ts +++ b/packages/typegpu/src/data/dataTypes.ts @@ -6,7 +6,6 @@ import type { InferPartial, InferPartialRecord, InferRecord, - IsValidVertexSchema, MemIdentityRecord, } from '../shared/repr.ts'; import type { @@ -15,6 +14,9 @@ import type { $memIdent, $repr, $reprPartial, + $validIndexSchema, + $validStorageSchema, + $validUniformSchema, $validVertexSchema, } from '../shared/symbols.ts'; import { $internal } from '../shared/symbols.ts'; @@ -47,13 +49,17 @@ export interface Disarray readonly type: 'disarray'; readonly elementCount: number; readonly elementType: TElement; + readonly [$validStorageSchema]: false; + readonly [$validUniformSchema]: false; + readonly [$validVertexSchema]: TElement[typeof $validVertexSchema]; + readonly [$validIndexSchema]: TElement extends + wgsl.U32 | wgsl.U16 | wgsl.Decorated ? true : false; // Type-tokens, not available at runtime readonly [$repr]: Infer[]; readonly [$reprPartial]: | { idx: number; value: InferPartial }[] | undefined; - readonly [$validVertexSchema]: IsValidVertexSchema; readonly [$invalidSchemaReason]: 'Disarrays are not host-shareable, use arrays instead'; // --- @@ -78,6 +84,12 @@ export interface Unstruct< (): Prettify>; readonly type: 'unstruct'; readonly propTypes: TProps; + readonly [$validStorageSchema]: false; + readonly [$validUniformSchema]: false; + readonly [$validVertexSchema]: { + [K in keyof TProps]: TProps[K][typeof $validVertexSchema]; + }[keyof TProps] extends true ? true : false; + readonly [$validIndexSchema]: false; // Type-tokens, not available at runtime readonly [$repr]: Prettify>; @@ -86,9 +98,6 @@ export interface Unstruct< readonly [$reprPartial]: | Prettify>> | undefined; - readonly [$validVertexSchema]: { - [K in keyof TProps]: IsValidVertexSchema; - }[keyof TProps] extends true ? true : false; readonly [$invalidSchemaReason]: 'Unstructs are not host-shareable, use structs instead'; // --- @@ -104,12 +113,13 @@ export interface LooseDecorated< readonly type: 'loose-decorated'; readonly inner: TInner; readonly attribs: TAttribs; + readonly [$validStorageSchema]: false; + readonly [$validUniformSchema]: false; + readonly [$validVertexSchema]: TInner[typeof $validVertexSchema]; + readonly [$validIndexSchema]: false; // Type-tokens, not available at runtime readonly [$repr]: Infer; - readonly [$invalidSchemaReason]: - 'Loosely decorated schemas are not host-shareable'; - readonly [$validVertexSchema]: IsValidVertexSchema; // --- } diff --git a/packages/typegpu/src/data/texture.ts b/packages/typegpu/src/data/texture.ts index e6183b4843..62622b58a0 100644 --- a/packages/typegpu/src/data/texture.ts +++ b/packages/typegpu/src/data/texture.ts @@ -1,5 +1,12 @@ import type { StorageTextureFormats } from '../core/texture/textureFormats.ts'; -import { $internal, $repr } from '../shared/symbols.ts'; +import { + $internal, + $repr, + $validIndexSchema, + $validStorageSchema, + $validUniformSchema, + $validVertexSchema, +} from '../shared/symbols.ts'; import type { Default, WithDefaults } from '../shared/utilityTypes.ts'; import { f32 } from './numeric.ts'; import type { F32 } from './wgslTypes.ts'; @@ -51,6 +58,10 @@ export interface WgslTexture< > extends BaseData { readonly [$repr]: unknown; readonly type: SampledTextureLiteral; + readonly [$validStorageSchema]: false; + readonly [$validUniformSchema]: false; + readonly [$validVertexSchema]: false; + readonly [$validIndexSchema]: false; readonly sampleType: ResolvedTextureProps['sampleType']; readonly dimension: ResolvedTextureProps['dimension']; @@ -63,6 +74,10 @@ export interface WgslStorageTexture< > extends BaseData { readonly [$repr]: unknown; readonly type: StorageTextureLiteral; + readonly [$validStorageSchema]: false; + readonly [$validUniformSchema]: false; + readonly [$validVertexSchema]: false; + readonly [$validIndexSchema]: false; readonly format: ResolvedStorageTextureProps['format']; readonly dimension: ResolvedStorageTextureProps['dimension']; @@ -72,6 +87,10 @@ export interface WgslStorageTexture< export interface WgslExternalTexture extends BaseData { readonly [$repr]: textureExternal; readonly type: 'texture_external'; + readonly [$validStorageSchema]: false; + readonly [$validUniformSchema]: false; + readonly [$validVertexSchema]: false; + readonly [$validIndexSchema]: false; readonly dimension: '2d'; } @@ -389,6 +408,10 @@ function createTexture( return { [$internal]: {}, + [$validStorageSchema]: false, + [$validUniformSchema]: false, + [$validVertexSchema]: false, + [$validIndexSchema]: false, [$repr]: undefined as unknown as WgslTexture, type, bindingSampleType: sampleTypes, @@ -402,6 +425,10 @@ function createStorageTexture( ): WgslStorageTexture { return { [$internal]: {}, + [$validStorageSchema]: false, + [$validUniformSchema]: false, + [$validVertexSchema]: false, + [$validIndexSchema]: false, [$repr]: undefined as unknown as WgslStorageTexture, type, ...props, @@ -802,6 +829,10 @@ export function textureExternal() { const key = 'texture_external'; return getOrCreate(key, () => ({ [$internal]: {}, + [$validStorageSchema]: false, + [$validUniformSchema]: false, + [$validVertexSchema]: false, + [$validIndexSchema]: false, [$repr]: undefined as unknown as textureExternal, type: 'texture_external', dimension: '2d', diff --git a/packages/typegpu/src/data/vertexFormatData.ts b/packages/typegpu/src/data/vertexFormatData.ts index d4a3494270..7f17075433 100644 --- a/packages/typegpu/src/data/vertexFormatData.ts +++ b/packages/typegpu/src/data/vertexFormatData.ts @@ -8,6 +8,9 @@ import type { Infer } from '../shared/repr.ts'; import type { $invalidSchemaReason, $repr, + $validIndexSchema, + $validStorageSchema, + $validUniformSchema, $validVertexSchema, } from '../shared/symbols.ts'; import type { VertexFormat } from '../shared/vertexFormat.ts'; @@ -59,24 +62,31 @@ export interface TgpuVertexFormatData // Type-tokens, not available at runtime readonly [$repr]: Infer>; readonly [$validVertexSchema]: true; - readonly [$invalidSchemaReason]: - 'Vertex formats are not host-shareable, use concrete types instead'; // --- } class TgpuVertexFormatDataImpl implements TgpuVertexFormatData { public readonly [$internal] = {}; + public readonly [$invalidSchemaReason]: string; + public readonly [$validStorageSchema]: false; + public readonly [$validUniformSchema]: false; + public readonly [$validVertexSchema]: true; + public readonly [$validIndexSchema]: false; [$gpuCallable]: TgpuVertexFormatData[typeof $gpuCallable]; // Type-tokens, not available at runtime declare readonly [$repr]: Infer>; - declare readonly [$validVertexSchema]: true; - declare readonly [$invalidSchemaReason]: - 'Vertex formats are not host-shareable, use concrete types instead'; // --- constructor(public readonly type: T) { + this[$invalidSchemaReason] = + 'Vertex formats are not host-shareable, use concrete types instead'; + this[$validStorageSchema] = false; + this[$validUniformSchema] = false; + this[$validVertexSchema] = true; + this[$validIndexSchema] = false; + this[$gpuCallable] = { call: (ctx, [v]): Snippet => { return schemaCallWrapperGPU(ctx, formatToWGSLType[this.type], v); diff --git a/packages/typegpu/src/data/wgslTypes.ts b/packages/typegpu/src/data/wgslTypes.ts index c8e3939dab..2cd386bf6d 100644 --- a/packages/typegpu/src/data/wgslTypes.ts +++ b/packages/typegpu/src/data/wgslTypes.ts @@ -7,21 +7,18 @@ import type { InferPartial, InferPartialRecord, InferRecord, - IsValidStorageSchema, - IsValidUniformSchema, - IsValidVertexSchema, MemIdentity, MemIdentityRecord, } from '../shared/repr.ts'; import type { $gpuRepr, - $invalidSchemaReason, + $invalidIndexSchema, + $invalidStorageSchema, + $invalidUniformSchema, + $invalidVertexSchema, $memIdent, $repr, $reprPartial, - $validStorageSchema, - $validUniformSchema, - $validVertexSchema, } from '../shared/symbols.ts'; import { $internal, isMarkedInternal } from '../shared/symbols.ts'; import type { Prettify, SwapNever } from '../shared/utilityTypes.ts'; @@ -40,6 +37,18 @@ export interface BaseData { readonly [$internal]: Record; readonly type: string; readonly [$repr]: unknown; + + readonly [$invalidStorageSchema]?: string | undefined; + readonly [$invalidUniformSchema]?: string | undefined; + readonly [$invalidVertexSchema]?: string | undefined; + readonly [$invalidIndexSchema]?: string | undefined; +} + +export interface NonHostShareableData extends BaseData { + readonly [$invalidStorageSchema]: TError; + readonly [$invalidUniformSchema]: TError; + readonly [$invalidVertexSchema]: TError; + readonly [$invalidIndexSchema]: TError; } export interface NumberArrayView { @@ -90,30 +99,30 @@ export interface matInfixNotation { /** * Represents a 64-bit integer. */ -export interface AbstractInt extends BaseData { +export interface AbstractInt + extends NonHostShareableData<'Abstract numerics are not host-shareable'> { readonly type: 'abstractInt'; // Type-tokens, not available at runtime readonly [$repr]: number; - readonly [$invalidSchemaReason]: 'Abstract numerics are not host-shareable'; // --- } /** * Represents a 64-bit IEEE 754 floating point number. */ -export interface AbstractFloat extends BaseData { +export interface AbstractFloat + extends NonHostShareableData<'Abstract numerics are not host-shareable'> { readonly type: 'abstractFloat'; // Type-tokens, not available at runtime readonly [$repr]: number; - readonly [$invalidSchemaReason]: 'Abstract numerics are not host-shareable'; // --- } -export interface Void extends BaseData { +export interface Void + extends NonHostShareableData<'Void is not host-shareable'> { readonly type: 'void'; // Type-tokens, not available at runtime readonly [$repr]: void; - readonly [$invalidSchemaReason]: 'Void is not host-shareable'; // --- } export const Void = { @@ -779,13 +788,12 @@ export type mBaseForVec = T extends v2f ? m2x2f * Cannot be used inside buffers as it is not host-shareable. */ export interface Bool - extends BaseData, DualFn<(v?: number | boolean) => boolean> { + extends + NonHostShareableData<'Bool is not host-shareable, use U32 or I32 instead'>, + DualFn<(v?: number | boolean) => boolean> { readonly type: 'bool'; - // Type-tokens, not available at runtime readonly [$repr]: boolean; - readonly [$invalidSchemaReason]: - 'Bool is not host-shareable, use U32 or I32 instead'; // --- } @@ -795,12 +803,10 @@ export interface Bool export interface F32 extends BaseData, DualFn<(v?: number | boolean) => number> { readonly type: 'f32'; + readonly [$invalidIndexSchema]: 'TODO: Add error here'; // Type-tokens, not available at runtime readonly [$repr]: number; - readonly [$validStorageSchema]: true; - readonly [$validUniformSchema]: true; - readonly [$validVertexSchema]: true; // --- } @@ -810,12 +816,10 @@ export interface F32 export interface F16 extends BaseData, DualFn<(v?: number | boolean) => number> { readonly type: 'f16'; + readonly [$invalidIndexSchema]: 'TODO: Add error here'; // Type-tokens, not available at runtime readonly [$repr]: number; - readonly [$validStorageSchema]: true; - readonly [$validUniformSchema]: true; - readonly [$validVertexSchema]: true; // --- } @@ -825,13 +829,11 @@ export interface F16 export interface I32 extends BaseData, DualFn<(v?: number | boolean) => number> { readonly type: 'i32'; + readonly [$invalidIndexSchema]: 'TODO: Add error here'; // Type-tokens, not available at runtime readonly [$repr]: number; readonly [$memIdent]: I32 | Atomic | DecoratedLocation; - readonly [$validStorageSchema]: true; - readonly [$validUniformSchema]: true; - readonly [$validVertexSchema]: true; // --- } @@ -841,13 +843,11 @@ export interface I32 export interface U32 extends BaseData, DualFn<(v?: number | boolean) => number> { readonly type: 'u32'; + readonly [$invalidIndexSchema]: 'TODO: Add error here'; // Type-tokens, not available at runtime readonly [$repr]: number; readonly [$memIdent]: U32 | Atomic | DecoratedLocation; - readonly [$validStorageSchema]: true; - readonly [$validUniformSchema]: true; - readonly [$validVertexSchema]: true; // --- } @@ -856,11 +856,15 @@ export interface U32 */ export interface U16 extends BaseData { readonly type: 'u16'; + readonly [$invalidStorageSchema]: + 'U16 is only usable inside arrays for index buffers, use U32 or I32 instead'; + readonly [$invalidUniformSchema]: + 'U16 is only usable inside arrays for index buffers, use U32 or I32 instead'; + readonly [$invalidVertexSchema]: + 'U16 is only usable inside arrays for index buffers, use U32 or I32 instead'; // Type-tokens, not available at runtime readonly [$repr]: number; - readonly [$invalidSchemaReason]: - 'U16 is only usable inside arrays for index buffers, use U32 or I32 instead'; // --- } @@ -877,13 +881,11 @@ export interface Vec2f extends > { readonly type: 'vec2f'; readonly primitive: F32; + readonly [$invalidIndexSchema]: 'TODO: Add error here'; readonly componentCount: 2; // Type-tokens, not available at runtime readonly [$repr]: v2f; - readonly [$validStorageSchema]: true; - readonly [$validUniformSchema]: true; - readonly [$validVertexSchema]: true; // --- } @@ -900,13 +902,11 @@ export interface Vec2h extends > { readonly type: 'vec2h'; readonly primitive: F16; + readonly [$invalidIndexSchema]: 'TODO: Add error here'; readonly componentCount: 2; // Type-tokens, not available at runtime readonly [$repr]: v2h; - readonly [$validStorageSchema]: true; - readonly [$validUniformSchema]: true; - readonly [$validVertexSchema]: true; // --- } @@ -923,13 +923,11 @@ export interface Vec2i extends > { readonly type: 'vec2i'; readonly primitive: I32; + readonly [$invalidIndexSchema]: 'TODO: Add error here'; readonly componentCount: 2; // Type-tokens, not available at runtime readonly [$repr]: v2i; - readonly [$validStorageSchema]: true; - readonly [$validUniformSchema]: true; - readonly [$validVertexSchema]: true; // --- } @@ -946,13 +944,11 @@ export interface Vec2u extends > { readonly type: 'vec2u'; readonly primitive: U32; + readonly [$invalidIndexSchema]: 'TODO: Add error here'; readonly componentCount: 2; // Type-tokens, not available at runtime readonly [$repr]: v2u; - readonly [$validStorageSchema]: true; - readonly [$validUniformSchema]: true; - readonly [$validVertexSchema]: true; // --- } @@ -961,7 +957,9 @@ export interface Vec2u extends * Cannot be used inside buffers as it is not host-shareable. */ export interface Vec2b extends - BaseData, + NonHostShareableData< + 'Boolean vectors is not host-shareable, use numeric vectors instead' + >, DualFn< & ((x: boolean, y: boolean) => v2b) & ((xy: boolean) => v2b) @@ -974,8 +972,6 @@ export interface Vec2b extends // Type-tokens, not available at runtime readonly [$repr]: v2b; - readonly [$invalidSchemaReason]: - 'Boolean vectors is not host-shareable, use numeric vectors instead'; // --- } @@ -994,13 +990,11 @@ export interface Vec3f extends > { readonly type: 'vec3f'; readonly primitive: F32; + readonly [$invalidIndexSchema]: 'TODO: Add error here'; readonly componentCount: 3; // Type-tokens, not available at runtime readonly [$repr]: v3f; - readonly [$validStorageSchema]: true; - readonly [$validUniformSchema]: true; - readonly [$validVertexSchema]: true; // --- } @@ -1019,13 +1013,11 @@ export interface Vec3h extends > { readonly type: 'vec3h'; readonly primitive: F16; + readonly [$invalidIndexSchema]: 'TODO: Add error here'; readonly componentCount: 3; // Type-tokens, not available at runtime readonly [$repr]: v3h; - readonly [$validStorageSchema]: true; - readonly [$validUniformSchema]: true; - readonly [$validVertexSchema]: true; // --- } @@ -1044,13 +1036,11 @@ export interface Vec3i extends > { readonly type: 'vec3i'; readonly primitive: I32; + readonly [$invalidIndexSchema]: 'TODO: Add error here'; readonly componentCount: 3; // Type-tokens, not available at runtime readonly [$repr]: v3i; - readonly [$validStorageSchema]: true; - readonly [$validUniformSchema]: true; - readonly [$validVertexSchema]: true; // --- } @@ -1069,13 +1059,11 @@ export interface Vec3u extends > { readonly type: 'vec3u'; readonly primitive: U32; + readonly [$invalidIndexSchema]: 'TODO: Add error here'; readonly componentCount: 3; // Type-tokens, not available at runtime readonly [$repr]: v3u; - readonly [$validStorageSchema]: true; - readonly [$validUniformSchema]: true; - readonly [$validVertexSchema]: true; // --- } @@ -1084,7 +1072,9 @@ export interface Vec3u extends * Cannot be used inside buffers as it is not host-shareable. */ export interface Vec3b extends - BaseData, + NonHostShareableData< + 'Boolean vectors is not host-shareable, use numeric vectors instead' + >, DualFn< & ((x: boolean, y: boolean, z: boolean) => v3b) & ((xyz: boolean) => v3b) @@ -1099,8 +1089,6 @@ export interface Vec3b extends // Type-tokens, not available at runtime readonly [$repr]: v3b; - readonly [$invalidSchemaReason]: - 'Boolean vectors is not host-shareable, use numeric vectors instead'; // --- } @@ -1123,13 +1111,11 @@ export interface Vec4f extends > { readonly type: 'vec4f'; readonly primitive: F32; + readonly [$invalidIndexSchema]: 'TODO: Add error here'; readonly componentCount: 4; // Type-tokens, not available at runtime readonly [$repr]: v4f; - readonly [$validStorageSchema]: true; - readonly [$validUniformSchema]: true; - readonly [$validVertexSchema]: true; // --- } @@ -1152,13 +1138,11 @@ export interface Vec4h extends > { readonly type: 'vec4h'; readonly primitive: F16; + readonly [$invalidIndexSchema]: 'TODO: Add error here'; readonly componentCount: 4; // Type-tokens, not available at runtime readonly [$repr]: v4h; - readonly [$validStorageSchema]: true; - readonly [$validUniformSchema]: true; - readonly [$validVertexSchema]: true; // --- } @@ -1181,13 +1165,11 @@ export interface Vec4i extends > { readonly type: 'vec4i'; readonly primitive: I32; + readonly [$invalidIndexSchema]: 'TODO: Add error here'; readonly componentCount: 4; // Type-tokens, not available at runtime readonly [$repr]: v4i; - readonly [$validStorageSchema]: true; - readonly [$validUniformSchema]: true; - readonly [$validVertexSchema]: true; // --- } @@ -1210,13 +1192,11 @@ export interface Vec4u extends > { readonly type: 'vec4u'; readonly primitive: U32; + readonly [$invalidIndexSchema]: 'TODO: Add error here'; readonly componentCount: 4; // Type-tokens, not available at runtime readonly [$repr]: v4u; - readonly [$validStorageSchema]: true; - readonly [$validUniformSchema]: true; - readonly [$validVertexSchema]: true; // --- } @@ -1225,7 +1205,9 @@ export interface Vec4u extends * Cannot be used inside buffers as it is not host-shareable. */ export interface Vec4b extends - BaseData, + NonHostShareableData< + 'Boolean vectors is not host-shareable, use numeric vectors instead' + >, DualFn< & ((x: boolean, y: boolean, z: boolean, w: boolean) => v4b) & ((xyzw: boolean) => v4b) @@ -1244,8 +1226,6 @@ export interface Vec4b extends // Type-tokens, not available at runtime readonly [$repr]: v4b; - readonly [$invalidSchemaReason]: - 'Boolean vectors is not host-shareable, use numeric vectors instead'; // --- } @@ -1254,12 +1234,12 @@ export interface Vec4b extends */ export interface Mat2x2f extends BaseData { readonly type: 'mat2x2f'; + readonly [$invalidVertexSchema]: 'TODO: Add error here'; + readonly [$invalidIndexSchema]: 'TODO: Add error here'; readonly primitive: F32; // Type-tokens, not available at runtime readonly [$repr]: m2x2f; - readonly [$validStorageSchema]: true; - readonly [$validUniformSchema]: true; // --- (...elements: [number, number, number, number]): m2x2f; @@ -1273,12 +1253,12 @@ export interface Mat2x2f extends BaseData { */ export interface Mat3x3f extends BaseData { readonly type: 'mat3x3f'; + readonly [$invalidVertexSchema]: 'TODO: Add error here'; + readonly [$invalidIndexSchema]: 'TODO: Add error here'; readonly primitive: F32; // Type-tokens, not available at runtime readonly [$repr]: m3x3f; - readonly [$validStorageSchema]: true; - readonly [$validUniformSchema]: true; // --- // deno-fmt-ignore @@ -1293,12 +1273,12 @@ export interface Mat3x3f extends BaseData { */ export interface Mat4x4f extends BaseData { readonly type: 'mat4x4f'; + readonly [$invalidVertexSchema]: 'TODO: Add error here'; + readonly [$invalidIndexSchema]: 'TODO: Add error here'; readonly primitive: F32; // Type-tokens, not available at runtime readonly [$repr]: m4x4f; - readonly [$validStorageSchema]: true; - readonly [$validUniformSchema]: true; // --- // deno-fmt-ignore @@ -1330,6 +1310,11 @@ export interface WgslArray readonly type: 'array'; readonly elementCount: number; readonly elementType: TElement; + readonly [$validStorageSchema]: TElement[typeof $validStorageSchema]; + readonly [$validUniformSchema]: TElement[typeof $validUniformSchema]; + readonly [$validVertexSchema]: TElement[typeof $validVertexSchema]; + readonly [$validIndexSchema]: TElement extends + U32 | U16 | Decorated ? true : false; // Type-tokens, not available at runtime readonly [$repr]: Infer[]; @@ -1338,9 +1323,6 @@ export interface WgslArray | { idx: number; value: InferPartial }[] | undefined; readonly [$memIdent]: WgslArray>; - readonly [$validStorageSchema]: IsValidStorageSchema; - readonly [$validUniformSchema]: IsValidUniformSchema; - readonly [$validVertexSchema]: IsValidVertexSchema; readonly [$invalidSchemaReason]: `in array element — ${ExtractInvalidSchemaError}`; // --- @@ -1364,6 +1346,16 @@ export interface WgslStruct< }; readonly type: 'struct'; readonly propTypes: TProps; + readonly [$validStorageSchema]: { + [K in keyof TProps]: TProps[K][typeof $validStorageSchema]; + }[keyof TProps] extends true ? true : false; + readonly [$validUniformSchema]: { + [K in keyof TProps]: TProps[K][typeof $validUniformSchema]; + }[keyof TProps] extends true ? true : false; + readonly [$validVertexSchema]: { + [K in keyof TProps]: TProps[K][typeof $validVertexSchema]; + }[keyof TProps] extends true ? true : false; + readonly [$validIndexSchema]: false; (props: Prettify>): Prettify>; (): Prettify>; @@ -1384,15 +1376,6 @@ export interface WgslStruct< }[keyof TProps], undefined >; - readonly [$validStorageSchema]: { - [K in keyof TProps]: IsValidStorageSchema; - }[keyof TProps] extends true ? true : false; - readonly [$validUniformSchema]: { - [K in keyof TProps]: IsValidUniformSchema; - }[keyof TProps] extends true ? true : false; - readonly [$validVertexSchema]: { - [K in keyof TProps]: IsValidVertexSchema; - }[keyof TProps] extends true ? true : false; // --- } @@ -1418,6 +1401,10 @@ export interface Ptr< readonly addressSpace: TAddr; readonly access: TAccess; readonly implicit: boolean; + readonly [$validStorageSchema]: false; + readonly [$validUniformSchema]: false; + readonly [$validVertexSchema]: false; + readonly [$validIndexSchema]: false; // Type-tokens, not available at runtime readonly [$repr]: ref>; @@ -1431,14 +1418,15 @@ export interface Ptr< export interface Atomic extends BaseData { readonly type: 'atomic'; readonly inner: TInner; + readonly [$validStorageSchema]: true; + readonly [$validUniformSchema]: true; + readonly [$validVertexSchema]: true; + readonly [$validIndexSchema]: false; // Type-tokens, not available at runtime readonly [$repr]: Infer; readonly [$gpuRepr]: TInner extends U32 ? atomicU32 : atomicI32; readonly [$memIdent]: MemIdentity; - readonly [$validStorageSchema]: true; - readonly [$validUniformSchema]: true; - readonly [$validVertexSchema]: true; // --- } @@ -1503,6 +1491,10 @@ export interface Decorated< readonly type: 'decorated'; readonly inner: TInner; readonly attribs: TAttribs; + readonly [$validStorageSchema]: TInner[typeof $validStorageSchema]; + readonly [$validUniformSchema]: TInner[typeof $validUniformSchema]; + readonly [$validVertexSchema]: TInner[typeof $validVertexSchema]; + readonly [$validIndexSchema]: false; // Type-tokens, not available at runtime readonly [$repr]: Infer; @@ -1511,10 +1503,6 @@ export interface Decorated< readonly [$memIdent]: TAttribs extends Location[] ? MemIdentity | Decorated, TAttribs> : Decorated, TAttribs>; - readonly [$validStorageSchema]: IsValidStorageSchema; - readonly [$validUniformSchema]: IsValidUniformSchema; - readonly [$validVertexSchema]: IsValidVertexSchema; - readonly [$invalidSchemaReason]: ExtractInvalidSchemaError; // --- } diff --git a/packages/typegpu/src/errors.ts b/packages/typegpu/src/errors.ts index 9b878ec86f..c75fdd1775 100644 --- a/packages/typegpu/src/errors.ts +++ b/packages/typegpu/src/errors.ts @@ -6,6 +6,7 @@ import type { BaseData, WgslArray } from './data/wgslTypes.ts'; import { getName, hasTinyestMetadata } from './shared/meta.ts'; import { DEV, TEST } from './shared/env.ts'; import type { TgpuBindGroupLayout } from './tgpuBindGroupLayout.ts'; +import { $internal } from './shared/symbols.ts'; const prefix = 'Invariant failed'; @@ -211,6 +212,10 @@ export class WgslTypeError extends Error { } } +export interface Illegal { + readonly [$internal]: unknown; +} + export class SignatureNotSupportedError extends Error { constructor(actual: BaseData[], candidates: BaseData[]) { super( diff --git a/packages/typegpu/src/shared/repr.ts b/packages/typegpu/src/shared/repr.ts index 4c1721ca8c..5c274f8816 100644 --- a/packages/typegpu/src/shared/repr.ts +++ b/packages/typegpu/src/shared/repr.ts @@ -1,17 +1,16 @@ 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 { BaseData, U16, U32, WgslArray } from '../data/wgslTypes.ts'; import type { $gpuRepr, $gpuValueOf, - $invalidSchemaReason, + $invalidIndexSchema, + $invalidStorageSchema, + $invalidUniformSchema, + $invalidVertexSchema, $memIdent, $repr, $reprPartial, - $validStorageSchema, - $validUniformSchema, - $validVertexSchema, } from './symbols.ts'; import type { ViewDimensionToDimension } from '../core/texture/textureFormats.ts'; import type { Default } from './utilityTypes.ts'; @@ -82,48 +81,6 @@ export type MemIdentityRecord< [Key in keyof T]: MemIdentity; }; -export type IsValidStorageSchema = - (T extends { readonly [$validStorageSchema]: true } ? true : false) extends // - // The check above can eval to `boolean` if parts of the union - // are valid, but some aren't. We only treat schemas invalid if all - // union elements are invalid. - false ? false - : true; - -export type IsValidUniformSchema = - (T extends { readonly [$validUniformSchema]: true } ? true : false) extends // - // The check above can eval to `boolean` if parts of the union - // are valid, but some aren't. We only treat schemas invalid if all - // union elements are invalid. - false ? false - : true; - -export type IsValidVertexSchema = - (T extends { readonly [$validVertexSchema]: true } ? true : false) extends // - // The check above can eval to `boolean` if parts of the union - // are valid, but some aren't. We only treat schemas invalid if all - // union elements are invalid. - false ? false - : true; - -/** - * Accepts only arrays (or disarrays) of u32 or u16. - */ -export type IsValidIndexSchema = Undecorate extends - WgslArray | Disarray - ? (Undecorate['elementType']>) extends U32 | U16 ? true : false - : false; - -/** - * Checks if a schema can be used in a buffer at all - */ -export type IsValidBufferSchema = ( - | IsValidStorageSchema - | IsValidUniformSchema - | IsValidVertexSchema - | IsValidIndexSchema -) extends false ? false : true; - /** * Validates if a texture can be used as sampled texture */ @@ -214,7 +171,28 @@ export type ValidateTextureViewSchema< ? SelfOrErrors> : never; -export type ExtractInvalidSchemaError = - [T] extends [{ readonly [$invalidSchemaReason]: string }] - ? `${TPrefix}${T[typeof $invalidSchemaReason]}` +export type ExtractInvalidStorageError = + [T] extends [{ readonly [$invalidStorageSchema]: string }] + ? `${TPrefix}${T[typeof $invalidStorageSchema]}` : never; + +export type ExtractInvalidUniformError = + [T] extends [{ readonly [$invalidUniformSchema]: string }] + ? `${TPrefix}${T[typeof $invalidUniformSchema]}` + : never; + +export type ExtractInvalidVertexError = + [T] extends [{ readonly [$invalidVertexSchema]: string }] + ? `${TPrefix}${T[typeof $invalidVertexSchema]}` + : never; + +export type ExtractInvalidIndexError = + [T] extends [{ readonly [$invalidIndexSchema]: string }] + ? `${TPrefix}${T[typeof $invalidIndexSchema]}` + : never; + +export type ExtractInvalidSchemaError = + | ExtractInvalidStorageError + | ExtractInvalidUniformError + | ExtractInvalidVertexError + | ExtractInvalidIndexError; diff --git a/packages/typegpu/src/shared/symbols.ts b/packages/typegpu/src/shared/symbols.ts index db94daa631..f740f43c32 100644 --- a/packages/typegpu/src/shared/symbols.ts +++ b/packages/typegpu/src/shared/symbols.ts @@ -58,29 +58,21 @@ export const $reprPartial = Symbol(`typegpu:${version}:$reprPartial`); */ export const $memIdent = Symbol(`typegpu:${version}:$memIdent`); -/** - * Type token, signaling that a schema can be used in a storage buffer. - */ -export const $validStorageSchema = Symbol( +/** Signaling that a schema cannot be used in a storage buffer. */ +export const $invalidStorageSchema = Symbol( `typegpu:${version}:$invalidStorageSchema`, ); -/** - * Type token, signaling that a schema can be used in a uniform buffer. - */ -export const $validUniformSchema = Symbol( - `typegpu:${version}:$validUniformSchema`, +/** Signaling that a schema cannot be used in a uniform buffer. */ +export const $invalidUniformSchema = Symbol( + `typegpu:${version}:$invalidUniformSchema`, ); -/** - * Type token, signaling that a schema can be used in a vertex buffer. - */ -export const $validVertexSchema = Symbol( - `typegpu:${version}:$validVertexSchema`, +/** Signaling that a schema cannot be used in a vertex buffer. */ +export const $invalidVertexSchema = Symbol( + `typegpu:${version}:$invalidVertexSchema`, ); -/** - * Type token, containing a reason for why the schema is invalid (if it is). - */ -export const $invalidSchemaReason = Symbol( - `typegpu:${version}:$invalidSchemaReason`, +/** Signaling that a schema cannot be used in an index buffer. */ +export const $invalidIndexSchema = Symbol( + `typegpu:${version}:$invalidIndexSchema`, ); export function isMarkedInternal( diff --git a/packages/typegpu/src/std/numeric.ts b/packages/typegpu/src/std/numeric.ts index 28b9859400..ea39f87594 100644 --- a/packages/typegpu/src/std/numeric.ts +++ b/packages/typegpu/src/std/numeric.ts @@ -34,6 +34,7 @@ import { type AnyMatInstance, type AnyNumericVecInstance, type AnySignedVecInstance, + type AnyWgslData, type BaseData, isHalfPrecisionSchema, isVecInstance, diff --git a/packages/typegpu/tests/buffer.test.ts b/packages/typegpu/tests/buffer.test.ts index 497d5fb153..78c884e7bb 100644 --- a/packages/typegpu/tests/buffer.test.ts +++ b/packages/typegpu/tests/buffer.test.ts @@ -1,12 +1,7 @@ -import { attest } from '@ark/attest'; import { describe, expect, expectTypeOf } from 'vitest'; import * as d from '../src/data/index.ts'; -import type { ValidateBufferSchema, ValidUsagesFor } from '../src/index.ts'; +import type { TgpuBuffer, ValidUsagesFor } from '../src/index.ts'; import { getName } from '../src/shared/meta.ts'; -import type { - IsValidBufferSchema, - IsValidUniformSchema, -} from '../src/shared/repr.ts'; import type { TypedArray } from '../src/shared/utilityTypes.ts'; import { it } from './utils/extendedIt.ts'; @@ -487,17 +482,12 @@ describe('TgpuBuffer', () => { ]); }); - it('should throw an error on the type level when using a schema containing boolean', ({ root }) => { + it('should choose a deprecated overload when using boolean schemas', ({ root }) => { const boolSchema = d.struct({ a: d.u32, b: d.bool, }); - // @ts-expect-error: boolean is not allowed in buffer schemas - attest(root.createBuffer(boolSchema)).type.errors.snap( - "Argument of type 'WgslStruct<{ a: U32; b: Bool; }>' is not assignable to parameter of type '\"(Error) in struct property 'b' — Bool is not host-shareable, use U32 or I32 instead\"'.", - ); - const nestedBoolSchema = d.struct({ a: d.u32, b: d.struct({ @@ -508,13 +498,55 @@ describe('TgpuBuffer', () => { }), }); - // @ts-expect-error: boolean is not allowed in buffer schemas - attest(root.createBuffer(nestedBoolSchema)).type.errors.snap( - "Argument of type 'WgslStruct<{ a: U32; b: WgslStruct<{ c: F32; d: WgslStruct<{ e: Bool; }>; }>; }>' is not assignable to parameter of type '\"(Error) in struct property 'b' — in struct property 'd' — in struct property 'e' — Bool is not host-shareable, use U32 or I32 instead\"'.", - ); + expectTypeOf(() => root.createBuffer(d.vec2b)) + .toEqualTypeOf<() => undefined>; + expect(() => root.createBuffer(d.vec2b)) + .toThrowErrorMatchingInlineSnapshot(); + + expectTypeOf(() => root.createBuffer(d.vec3b)) + .toEqualTypeOf<() => undefined>; + expect(() => root.createBuffer(d.vec3b)) + .toThrowErrorMatchingInlineSnapshot(); + + expectTypeOf(() => root.createBuffer(d.vec4b)) + .toEqualTypeOf<() => undefined>; + expect(() => root.createBuffer(d.vec4b)) + .toThrowErrorMatchingInlineSnapshot(); + + expectTypeOf(() => root.createBuffer(d.bool)) + .toEqualTypeOf<() => undefined>; + expect(() => root.createBuffer(d.bool)) + .toThrowErrorMatchingInlineSnapshot(); + + expectTypeOf(() => root.createBuffer(d.arrayOf(d.bool, 2))) + .toEqualTypeOf<() => undefined>(); + expect(() => root.createBuffer(d.arrayOf(d.bool, 2))) + .toThrowErrorMatchingInlineSnapshot(); + + expectTypeOf(() => root.createBuffer(d.arrayOf(d.arrayOf(d.bool, 2), 2))) + .toEqualTypeOf<() => undefined>(); + expect(() => root.createBuffer(d.arrayOf(d.arrayOf(d.bool, 2), 2))) + .toThrowErrorMatchingInlineSnapshot(); + + expectTypeOf(() => root.createBuffer(boolSchema)) + .toEqualTypeOf<() => undefined>(); + expect(() => root.createBuffer(boolSchema)) + .toThrowErrorMatchingInlineSnapshot(); + + expectTypeOf(() => root.createBuffer(nestedBoolSchema)) + .toEqualTypeOf<() => undefined>(); + expect(() => root.createBuffer(nestedBoolSchema)) + .toThrowErrorMatchingInlineSnapshot(); }); - it('should throw an error on the type level when using a u16 schema outside of an array', ({ root }) => { + it('should choose a deprecated overload when using pointer schemas', ({ root }) => { + expectTypeOf(() => root.createBuffer(d.ptrFn(d.f32))) + .toEqualTypeOf<() => undefined>; + expect(() => root.createBuffer(d.ptrFn(d.f32))) + .toThrowErrorMatchingInlineSnapshot(); + }); + + it('should throw an error when using a u16 schema outside of an array', ({ root }) => { const fine = d.arrayOf(d.u16, 32); root.createBuffer(fine); @@ -523,10 +555,10 @@ describe('TgpuBuffer', () => { b: d.u32, }); - // @ts-expect-error - attest(root.createBuffer(notFine)).type.errors.snap( - "Argument of type 'WgslStruct<{ a: U16; b: U32; }>' is not assignable to parameter of type '\"(Error) in struct property 'a' — U16 is only usable inside arrays for index buffers, use U32 or I32 instead\"'.", - ); + expectTypeOf(() => root.createBuffer(notFine)) + .toEqualTypeOf<() => undefined>(); + expect(() => root.createBuffer(notFine)) + .toThrowErrorMatchingInlineSnapshot(); const alsoNotFine = d.struct({ a: d.u32, @@ -534,10 +566,10 @@ describe('TgpuBuffer', () => { c: d.f32, }); - // @ts-expect-error - attest(root.createBuffer(alsoNotFine)).type.errors.snap( - "Argument of type 'WgslStruct<{ a: U32; b: WgslArray; c: F32; }>' is not assignable to parameter of type '\"(Error) in struct property 'b' — in array element — U16 is only usable inside arrays for index buffers, use U32 or I32 instead\"'.", - ); + expectTypeOf(() => root.createBuffer(alsoNotFine)) + .toEqualTypeOf<() => undefined>(); + expect(() => root.createBuffer(alsoNotFine)) + .toThrowErrorMatchingInlineSnapshot(); }); it('should only allow index usage for valid u16 schemas', ({ root }) => { @@ -572,86 +604,20 @@ describe('TgpuBuffer', () => { ] >(); }); -}); - -describe('IsValidUniformSchema', () => { - it('treats booleans as invalid', () => { - expectTypeOf>().toEqualTypeOf(); - }); - - it('treats numeric schemas as valid', () => { - expectTypeOf>().toEqualTypeOf(); - }); - - it('it treats union schemas as valid (even if they contain booleans)', () => { - expectTypeOf>() - .toEqualTypeOf(); - expectTypeOf>>() - .toEqualTypeOf(); - expectTypeOf>>() - .toEqualTypeOf(); - }); -}); - -describe('IsValidBufferSchema', () => { - it('treats booleans as invalid', () => { - expectTypeOf>().toEqualTypeOf(); - }); - - it('treats schemas holding booleans as invalid', () => { - expectTypeOf>>() - .toEqualTypeOf(); - expectTypeOf>>() - .toEqualTypeOf(); - }); - - it('treats other schemas as valid', () => { - expectTypeOf>().toEqualTypeOf(); - }); - - it('it treats arrays of valid schemas as valid', () => { - expectTypeOf>>() - .toEqualTypeOf(); - }); - - it('it treats union schemas as valid (even if they contain booleans)', () => { - expectTypeOf>() - .toEqualTypeOf(); - expectTypeOf>>() - .toEqualTypeOf(); - expectTypeOf>>() - .toEqualTypeOf(); - }); -}); - -describe('ValidateBufferSchema', () => { - it('is strict for exact types', () => { - expectTypeOf>().toEqualTypeOf(); - expectTypeOf>().toEqualTypeOf< - '(Error) Bool is not host-shareable, use U32 or I32 instead' - >(); - }); - - // Could be not host-shareable, but we let it go to not be annoying - it('is lenient for union types', () => { - expectTypeOf>().toEqualTypeOf< - d.U32 | d.Bool - >(); - - expectTypeOf>().toEqualTypeOf< - d.AnyData - >(); - }); it('can be used to wrap `createBuffer` in a generic function (schema and usages customizable)', ({ root }) => { - function createMyBuffer( - schema: ValidateBufferSchema, + function createMyBuffer( + schema: T, usages: [ValidUsagesFor, ...ValidUsagesFor[]], ) { const buffer = root.createBuffer(schema).$usage(...usages); return buffer; } + const hello = root.createBuffer(d.bool); + + hello.$; + // Invalid // @ts-expect-error: Cannot create buffers with bools in them (() => createMyBuffer(d.bool, [''])); @@ -662,4 +628,15 @@ describe('ValidateBufferSchema', () => { createMyBuffer(d.f32, ['uniform']); createMyBuffer(d.unorm8x4, ['vertex']); }); + + it('accepts wide schemas', ({ root }) => { + const wideSchema = d.f32 as d.AnyData; + const widerSchema = d.f32 as d.BaseData; + + expectTypeOf(() => root.createBuffer(wideSchema)) + .toEqualTypeOf<() => TgpuBuffer>(); + + expectTypeOf(() => root.createBuffer(widerSchema)) + .toEqualTypeOf<() => TgpuBuffer>(); + }); });