typegpu
Version:
A thin layer between JS and WebGPU/WGSL that improves development experience and allows for faster iteration.
154 lines (153 loc) • 5.74 kB
JavaScript
import { getName, hasTinyestMetadata } from "./shared/meta.js";
import { DEV, TEST } from "./shared/env.js";
const prefix = 'Invariant failed';
/**
* Inspired by: https://github.com/alexreardon/tiny-invariant/blob/master/src/tiny-invariant.ts
*/
export function invariant(condition, message) {
if (condition) {
// Condition passed
return;
}
// In production we strip the message but still throw
if (!DEV && !TEST) {
throw new Error(prefix);
}
// When not in production we allow the message to pass through
// *This block will be removed in production builds*
const provided = typeof message === 'function' ? message() : message;
// Options:
// 1. message provided: `${prefix}: ${provided}`
// 2. message not provided: prefix
const value = provided ? `${prefix}: ${provided}` : prefix;
throw new Error(value);
}
/**
* An error that happens during resolution of WGSL code.
* Contains a trace of all ancestor resolvables in
* which this error originated.
*
* @category Errors
*/
export class ResolutionError extends Error {
cause;
trace;
constructor(cause, trace) {
let entries = trace.map((ancestor) => `- ${hasTinyestMetadata(ancestor) ? `fn*:${getName(ancestor)}` : ancestor}`);
// Showing only the root and leaf nodes.
if (entries.length > 20) {
entries = [...entries.slice(0, 11), '...', ...entries.slice(-10)];
}
super(`Resolution of the following tree failed:\n${entries.join('\n')}: ${cause && typeof cause === 'object' && 'message' in cause ? cause.message : cause}`);
this.cause = cause;
this.trace = trace;
// Set the prototype explicitly.
Object.setPrototypeOf(this, ResolutionError.prototype);
}
appendToTrace(ancestor) {
const newTrace = [ancestor, ...this.trace];
return new ResolutionError(this.cause, newTrace);
}
}
/**
* An error that happens during execution of TypeGPU functions.
* Contains a trace of all TypeGPU functions called along the way.
*
* @category Errors
*/
export class ExecutionError extends Error {
cause;
trace;
constructor(cause, trace) {
let entries = trace.map((ancestor) => `- ${ancestor}`);
// Showing only the root and leaf nodes.
if (entries.length > 20) {
entries = [...entries.slice(0, 11), '...', ...entries.slice(-10)];
}
super(`Execution of the following tree failed:\n${entries.join('\n')}: ${cause && typeof cause === 'object' && 'message' in cause ? cause.message : cause}`);
this.cause = cause;
this.trace = trace;
// Set the prototype explicitly.
Object.setPrototypeOf(this, ExecutionError.prototype);
}
appendToTrace(ancestor) {
const newTrace = [ancestor, ...this.trace];
return new ExecutionError(this.cause, newTrace);
}
}
/**
* @category Errors
*/
export class MissingSlotValueError extends Error {
slot;
constructor(slot) {
super(`Missing value for '${slot}'`);
this.slot = slot;
// Set the prototype explicitly.
Object.setPrototypeOf(this, MissingSlotValueError.prototype);
}
}
/**
* @category Errors
*/
export class NotUniformError extends Error {
constructor(value) {
super(`Buffer '${getName(value) ?? '<unnamed>'}' is not bindable as a uniform. Use .$usage('uniform') to allow it.`);
// Set the prototype explicitly.
Object.setPrototypeOf(this, NotUniformError.prototype);
}
}
export class MissingBindGroupsError extends Error {
constructor(layouts) {
super(`Missing bind groups for layouts: '${[...layouts]
.map((layout) => getName(layout) ?? '<unnamed>')
.join(', ')}'. Please provide it using pipeline.with(bindGroup).(...)`);
// Set the prototype explicitly.
Object.setPrototypeOf(this, MissingBindGroupsError.prototype);
}
}
export class MissingVertexBuffersError extends Error {
constructor(layouts) {
super(`Missing vertex buffers for layouts: '${[...layouts]
.map((layout) => getName(layout) ?? '<unnamed>')
.join(', ')}'. Please provide it using pipeline.with(layout, buffer).(...)`);
// Set the prototype explicitly.
Object.setPrototypeOf(this, MissingVertexBuffersError.prototype);
}
}
export class IllegalVarAccessError extends Error {
constructor(msg) {
super(msg);
// Set the prototype explicitly.
Object.setPrototypeOf(this, IllegalVarAccessError.prototype);
}
}
export class IllegalBufferAccessError extends Error {
constructor(msg) {
super(msg);
// Set the prototype explicitly.
Object.setPrototypeOf(this, IllegalBufferAccessError.prototype);
}
}
export class WgslTypeError extends Error {
constructor(msg) {
super(msg);
// Set the prototype explicitly.
Object.setPrototypeOf(this, WgslTypeError.prototype);
}
}
export class SignatureNotSupportedError extends Error {
constructor(actual, candidates) {
super(`Unsupported data types: ${actual
.map((a) => a.type)
.join(', ')}. Supported types are: ${candidates.map((r) => r.type).join(', ')}.`);
// Set the prototype explicitly.
Object.setPrototypeOf(this, SignatureNotSupportedError.prototype);
}
}
export class FiniteMathAssumptionError extends Error {
constructor(value, type) {
super(`Cannot convert value '${value}' to type ${type.type} because of the Finite Math Assumption (see: https://www.w3.org/TR/WGSL/#finite-math-assumption)`);
Object.setPrototypeOf(this, FiniteMathAssumptionError.prototype);
}
}