typegpu 0.8.2 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/builtin-ClEnM-Ye.js +818 -0
- package/builtin-ClEnM-Ye.js.map +1 -0
- package/chunk-BYypO7fO.js +18 -0
- package/common/index.d.ts +8 -23
- package/common/index.d.ts.map +1 -0
- package/common/index.js +7 -5
- package/common/index.js.map +1 -1
- package/data/index.d.ts +7 -400
- package/data/index.d.ts.map +1 -0
- package/data/index.js +164 -1
- package/data/index.js.map +1 -1
- package/deepEqual-yZXvaV2C.js +413 -0
- package/deepEqual-yZXvaV2C.js.map +1 -0
- package/extensions-0SFbU9FH.js +2032 -0
- package/extensions-0SFbU9FH.js.map +1 -0
- package/fullScreenTriangle-MdLGaAMR.js +543 -0
- package/fullScreenTriangle-MdLGaAMR.js.map +1 -0
- package/index.d.ts +167 -264
- package/index.d.ts.map +1 -0
- package/index.js +6294 -160
- package/index.js.map +1 -1
- package/indexNamedExports-Cdy7USiY.d.ts +5696 -0
- package/indexNamedExports-Cdy7USiY.d.ts.map +1 -0
- package/operators-HTxa_0k9.js +4156 -0
- package/operators-HTxa_0k9.js.map +1 -0
- package/package.json +3 -2
- package/std/index.d.ts +7 -637
- package/std/index.d.ts.map +1 -0
- package/std/index.js +165 -1
- package/std/index.js.map +1 -1
- package/texture-Dg5ybJro.js +205 -0
- package/texture-Dg5ybJro.js.map +1 -0
- package/chunk-6U5HPHCJ.js +0 -2
- package/chunk-6U5HPHCJ.js.map +0 -1
- package/chunk-CGQB3SER.js +0 -3
- package/chunk-CGQB3SER.js.map +0 -1
- package/chunk-CRZWTZM2.js +0 -10
- package/chunk-CRZWTZM2.js.map +0 -1
- package/chunk-ECR2EGZX.js +0 -7
- package/chunk-ECR2EGZX.js.map +0 -1
- package/chunk-PWBIFP67.js +0 -2
- package/chunk-PWBIFP67.js.map +0 -1
- package/matrix-DIfOiRyz.d.ts +0 -122
- package/tgpuConstant-BTQFNlQH.d.ts +0 -5201
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
import { Cn as isDisarray, Dn as undecorate, En as isUnstruct, Nn as isDecorated, Tn as isLooseDecorated, Un as isVec, Vn as isPtr, Yn as isWgslStruct, cr as $internal, dr as $repr, er as getName, gt as schemaCallWrapper, jn as isAtomic, qn as isWgslArray, rr as setName, w as comptime } from "./operators-HTxa_0k9.js";
|
|
2
|
+
import { _ as roundUp, b as customAlignmentOf, g as getLayoutInfo, h as sizeOf, y as alignmentOf } from "./builtin-ClEnM-Ye.js";
|
|
3
|
+
import { Measurer } from "typed-binary";
|
|
4
|
+
|
|
5
|
+
//#region src/data/sampler.ts
|
|
6
|
+
function sampler() {
|
|
7
|
+
return {
|
|
8
|
+
[$internal]: {},
|
|
9
|
+
type: "sampler",
|
|
10
|
+
[$repr]: void 0
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
function comparisonSampler() {
|
|
14
|
+
return {
|
|
15
|
+
[$internal]: {},
|
|
16
|
+
type: "sampler_comparison",
|
|
17
|
+
[$repr]: void 0
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function isWgslSampler(value) {
|
|
21
|
+
return !!value[$internal] && value.type === "sampler";
|
|
22
|
+
}
|
|
23
|
+
function isWgslComparisonSampler(value) {
|
|
24
|
+
return !!value[$internal] && value.type === "sampler_comparison";
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region src/data/alignIO.ts
|
|
29
|
+
/**
|
|
30
|
+
* @param io the IO to align
|
|
31
|
+
* @param baseAlignment must be power of 2
|
|
32
|
+
*/
|
|
33
|
+
function alignIO(io, baseAlignment) {
|
|
34
|
+
const currentPos = "size" in io ? io.size : io.currentByteOffset;
|
|
35
|
+
const bitMask = baseAlignment - 1;
|
|
36
|
+
const offset = currentPos & bitMask;
|
|
37
|
+
if ("skipBytes" in io) io.skipBytes(baseAlignment - offset & bitMask);
|
|
38
|
+
else io.add(baseAlignment - offset & bitMask);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
//#endregion
|
|
42
|
+
//#region src/data/offsets.ts
|
|
43
|
+
const cachedOffsets = /* @__PURE__ */ new WeakMap();
|
|
44
|
+
function offsetsForProps(struct) {
|
|
45
|
+
const cached = cachedOffsets.get(struct);
|
|
46
|
+
if (cached) return cached;
|
|
47
|
+
const measurer = new Measurer();
|
|
48
|
+
const offsets = {};
|
|
49
|
+
let lastEntry;
|
|
50
|
+
for (const key in struct.propTypes) {
|
|
51
|
+
const prop = struct.propTypes[key];
|
|
52
|
+
if (prop === void 0) throw new Error(`Property ${key} is undefined in struct`);
|
|
53
|
+
const beforeAlignment = measurer.size;
|
|
54
|
+
alignIO(measurer, isUnstruct(struct) ? customAlignmentOf(prop) : alignmentOf(prop));
|
|
55
|
+
if (lastEntry) lastEntry.padding = measurer.size - beforeAlignment;
|
|
56
|
+
const propSize = sizeOf(prop);
|
|
57
|
+
offsets[key] = {
|
|
58
|
+
offset: measurer.size,
|
|
59
|
+
size: propSize
|
|
60
|
+
};
|
|
61
|
+
lastEntry = offsets[key];
|
|
62
|
+
measurer.add(propSize);
|
|
63
|
+
}
|
|
64
|
+
if (lastEntry) lastEntry.padding = roundUp(sizeOf(struct), alignmentOf(struct)) - measurer.size;
|
|
65
|
+
cachedOffsets.set(struct, offsets);
|
|
66
|
+
return offsets;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
//#endregion
|
|
70
|
+
//#region src/data/atomic.ts
|
|
71
|
+
/**
|
|
72
|
+
* Marks a concrete integer scalar type schema (u32 or i32) as a WGSL atomic.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* const atomicU32 = d.atomic(d.u32);
|
|
76
|
+
* const atomicI32 = d.atomic(d.i32);
|
|
77
|
+
*
|
|
78
|
+
* @param data Underlying type schema.
|
|
79
|
+
*/
|
|
80
|
+
function atomic(data) {
|
|
81
|
+
return new AtomicImpl(data);
|
|
82
|
+
}
|
|
83
|
+
var AtomicImpl = class {
|
|
84
|
+
[$internal] = {};
|
|
85
|
+
type = "atomic";
|
|
86
|
+
constructor(inner) {
|
|
87
|
+
this.inner = inner;
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
//#endregion
|
|
92
|
+
//#region src/data/isContiguous.ts
|
|
93
|
+
function isContiguous(schema) {
|
|
94
|
+
return getLayoutInfo(schema, "isContiguous");
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Returns `true` if data represented by the `schema` doesn't have padding.
|
|
98
|
+
*/
|
|
99
|
+
function PUBLIC_isContiguous(schema) {
|
|
100
|
+
return isContiguous(schema);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
//#endregion
|
|
104
|
+
//#region src/data/getLongestContiguousPrefix.ts
|
|
105
|
+
function getLongestContiguousPrefix(schema) {
|
|
106
|
+
return getLayoutInfo(schema, "longestContiguousPrefix");
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Returns the size (in bytes) of the longest contiguous memory prefix of data represented by the `schema`.
|
|
110
|
+
*/
|
|
111
|
+
function PUBLIC_getLongestContiguousPrefix(schema) {
|
|
112
|
+
return getLongestContiguousPrefix(schema);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
//#endregion
|
|
116
|
+
//#region src/data/offsetUtils.ts
|
|
117
|
+
const OFFSET_MARKER = Symbol("indirectOffset");
|
|
118
|
+
const CONTIGUOUS_MARKER = Symbol("indirectContiguous");
|
|
119
|
+
function isOffsetProxy(value) {
|
|
120
|
+
return typeof value === "object" && value !== null && OFFSET_MARKER in value && CONTIGUOUS_MARKER in value;
|
|
121
|
+
}
|
|
122
|
+
function scalarNode(offset, contiguous) {
|
|
123
|
+
return {
|
|
124
|
+
[OFFSET_MARKER]: offset,
|
|
125
|
+
[CONTIGUOUS_MARKER]: contiguous
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
function getMarker(target, prop) {
|
|
129
|
+
if (prop === OFFSET_MARKER) return target[OFFSET_MARKER];
|
|
130
|
+
if (prop === CONTIGUOUS_MARKER) return target[CONTIGUOUS_MARKER];
|
|
131
|
+
}
|
|
132
|
+
function makeProxy(schema, baseOffset, contiguous = sizeOf(schema)) {
|
|
133
|
+
const unwrapped = undecorate(schema);
|
|
134
|
+
const vecComponentCount = isVec(unwrapped) ? unwrapped.componentCount : void 0;
|
|
135
|
+
if (vecComponentCount !== void 0) {
|
|
136
|
+
const componentSize = sizeOf(unwrapped.primitive);
|
|
137
|
+
return makeVecProxy(scalarNode(baseOffset, contiguous), componentSize, vecComponentCount);
|
|
138
|
+
}
|
|
139
|
+
if (isWgslStruct(unwrapped)) return makeStructProxy(unwrapped, scalarNode(baseOffset, contiguous));
|
|
140
|
+
if (isWgslArray(unwrapped)) return makeArrayProxy(unwrapped, scalarNode(baseOffset, contiguous));
|
|
141
|
+
return scalarNode(baseOffset, contiguous);
|
|
142
|
+
}
|
|
143
|
+
function createOffsetProxy(schema, baseOffset = 0) {
|
|
144
|
+
return makeProxy(schema, baseOffset, sizeOf(schema));
|
|
145
|
+
}
|
|
146
|
+
function makeVecProxy(target, componentSize, componentCount) {
|
|
147
|
+
const baseOffset = target[OFFSET_MARKER];
|
|
148
|
+
return new Proxy(target, { get(t, prop) {
|
|
149
|
+
const marker = getMarker(t, prop);
|
|
150
|
+
if (marker !== void 0) return marker;
|
|
151
|
+
const idx = prop === "x" || prop === "0" ? 0 : prop === "y" || prop === "1" ? 1 : prop === "z" || prop === "2" ? 2 : prop === "w" || prop === "3" ? 3 : -1;
|
|
152
|
+
if (idx < 0 || idx >= componentCount) return;
|
|
153
|
+
const byteOffset = idx * componentSize;
|
|
154
|
+
const contiguous = Math.max(0, t[CONTIGUOUS_MARKER] - byteOffset);
|
|
155
|
+
return scalarNode(baseOffset + byteOffset, contiguous);
|
|
156
|
+
} });
|
|
157
|
+
}
|
|
158
|
+
function makeArrayProxy(array, target) {
|
|
159
|
+
const elementType = array.elementType;
|
|
160
|
+
const elementSize = sizeOf(elementType);
|
|
161
|
+
const stride = roundUp(elementSize, alignmentOf(elementType));
|
|
162
|
+
const hasPadding = stride > elementSize;
|
|
163
|
+
return new Proxy(target, { get(t, prop) {
|
|
164
|
+
const marker = getMarker(t, prop);
|
|
165
|
+
if (marker !== void 0) return marker;
|
|
166
|
+
if (prop === "length") return array.elementCount;
|
|
167
|
+
if (typeof prop !== "string") return;
|
|
168
|
+
const index = Number(prop);
|
|
169
|
+
if (!Number.isInteger(index) || index < 0 || index >= array.elementCount) return;
|
|
170
|
+
const elementOffset = index * stride;
|
|
171
|
+
const remainingFromHere = !isContiguous(elementType) ? elementSize + getLongestContiguousPrefix(elementType) : Math.max(0, t[CONTIGUOUS_MARKER] - elementOffset);
|
|
172
|
+
const childContiguous = hasPadding ? Math.min(remainingFromHere, elementSize) : remainingFromHere;
|
|
173
|
+
return makeProxy(elementType, t[OFFSET_MARKER] + elementOffset, childContiguous);
|
|
174
|
+
} });
|
|
175
|
+
}
|
|
176
|
+
function makeStructProxy(struct, target) {
|
|
177
|
+
const offsets = offsetsForProps(struct);
|
|
178
|
+
const propTypes = struct.propTypes;
|
|
179
|
+
const propNames = Object.keys(propTypes);
|
|
180
|
+
const meta = /* @__PURE__ */ new Map();
|
|
181
|
+
let runStart = 0;
|
|
182
|
+
for (let i = 0; i < propNames.length; i++) {
|
|
183
|
+
const name = propNames[i];
|
|
184
|
+
if (!name) continue;
|
|
185
|
+
const type = propTypes[name];
|
|
186
|
+
if (!type) continue;
|
|
187
|
+
const info = offsets[name];
|
|
188
|
+
const padding = info.padding ?? 0;
|
|
189
|
+
const typeContiguous = isContiguous(type);
|
|
190
|
+
if (!(i === propNames.length - 1 || padding > 0 || !typeContiguous)) continue;
|
|
191
|
+
const runEnd = info.offset + (typeContiguous ? info.size : getLongestContiguousPrefix(type));
|
|
192
|
+
for (let j = runStart; j <= i; j++) {
|
|
193
|
+
const runName = propNames[j];
|
|
194
|
+
if (!runName) continue;
|
|
195
|
+
const runInfo = offsets[runName];
|
|
196
|
+
meta.set(runName, {
|
|
197
|
+
offset: runInfo.offset,
|
|
198
|
+
runEnd
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
runStart = i + 1;
|
|
202
|
+
}
|
|
203
|
+
return new Proxy(target, { get(t, prop) {
|
|
204
|
+
const marker = getMarker(t, prop);
|
|
205
|
+
if (marker !== void 0) return marker;
|
|
206
|
+
if (typeof prop !== "string") return;
|
|
207
|
+
const m = meta.get(prop);
|
|
208
|
+
if (!m) return;
|
|
209
|
+
const remainingFromHere = Math.max(0, t[CONTIGUOUS_MARKER] - m.offset);
|
|
210
|
+
const localLimit = Math.max(0, m.runEnd - m.offset);
|
|
211
|
+
const propSchema = propTypes[prop];
|
|
212
|
+
if (!propSchema) return;
|
|
213
|
+
return makeProxy(propSchema, t[OFFSET_MARKER] + m.offset, sizeOf(struct) === m.runEnd ? remainingFromHere : localLimit);
|
|
214
|
+
} });
|
|
215
|
+
}
|
|
216
|
+
function getRootContiguous(schema) {
|
|
217
|
+
const unwrapped = undecorate(schema);
|
|
218
|
+
if (isWgslStruct(unwrapped)) {
|
|
219
|
+
const offsets = offsetsForProps(unwrapped);
|
|
220
|
+
const propTypes = unwrapped.propTypes;
|
|
221
|
+
const propNames = Object.keys(propTypes);
|
|
222
|
+
for (let i = 0; i < propNames.length; i++) {
|
|
223
|
+
const name = propNames[i];
|
|
224
|
+
if (!name) continue;
|
|
225
|
+
const info = offsets[name];
|
|
226
|
+
const padding = info.padding ?? 0;
|
|
227
|
+
const runEnd = info.offset + info.size;
|
|
228
|
+
if (i === propNames.length - 1 || padding > 0) return runEnd;
|
|
229
|
+
}
|
|
230
|
+
return 0;
|
|
231
|
+
}
|
|
232
|
+
if (isWgslArray(unwrapped)) {
|
|
233
|
+
const elementType = unwrapped.elementType;
|
|
234
|
+
const elementSize = sizeOf(elementType);
|
|
235
|
+
const stride = roundUp(elementSize, alignmentOf(elementType));
|
|
236
|
+
const totalSize = sizeOf(schema);
|
|
237
|
+
if (!Number.isFinite(totalSize)) return elementSize;
|
|
238
|
+
return stride > elementSize ? elementSize : totalSize;
|
|
239
|
+
}
|
|
240
|
+
return sizeOf(schema);
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* A function that retrieves offset and information for a specific primitive within a data schema.
|
|
244
|
+
* Example usage:
|
|
245
|
+
* ```ts
|
|
246
|
+
* const Boid = d.struct({
|
|
247
|
+
* position: d.vec3f,
|
|
248
|
+
* velocity: d.vec3f,
|
|
249
|
+
* });
|
|
250
|
+
* const memLayout = d.memoryLayoutOf(Boid, (b) => b.velocity.y);
|
|
251
|
+
* console.log(memLayout.offset); // Byte offset of velocity.y within Boid (here 20 bytes)
|
|
252
|
+
* console.log(memLayout.contiguous); // Contiguous bytes available from that offset (here 8 bytes)
|
|
253
|
+
* ```
|
|
254
|
+
*
|
|
255
|
+
* @param schema - The data schema to analyze.
|
|
256
|
+
* @param accessor - Optional function that accesses a specific primitive within the schema. If omitted, uses the root offset (0).
|
|
257
|
+
* @returns An object containing the offset and contiguous byte information.
|
|
258
|
+
*/
|
|
259
|
+
function memoryLayoutOf(schema, accessor) {
|
|
260
|
+
if (!accessor) return {
|
|
261
|
+
offset: 0,
|
|
262
|
+
contiguous: getRootContiguous(schema)
|
|
263
|
+
};
|
|
264
|
+
const result = accessor(createOffsetProxy(schema));
|
|
265
|
+
if (isOffsetProxy(result)) return {
|
|
266
|
+
offset: result[OFFSET_MARKER],
|
|
267
|
+
contiguous: result[CONTIGUOUS_MARKER]
|
|
268
|
+
};
|
|
269
|
+
throw new Error("Invalid accessor result. Expected an offset proxy with markers.");
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
//#endregion
|
|
273
|
+
//#region src/data/disarray.ts
|
|
274
|
+
/**
|
|
275
|
+
* Creates an array schema that can be used to construct vertex buffers.
|
|
276
|
+
* Describes arrays with fixed-size length, storing elements of the same type.
|
|
277
|
+
*
|
|
278
|
+
* Elements in the schema are not aligned in respect to their `byteAlignment`,
|
|
279
|
+
* unless they are explicitly decorated with the custom align attribute
|
|
280
|
+
* via `d.align` function.
|
|
281
|
+
*
|
|
282
|
+
* @example
|
|
283
|
+
* const disarray = d.disarrayOf(d.vec3f, 3); // packed array of vec3f
|
|
284
|
+
*
|
|
285
|
+
* @example
|
|
286
|
+
* const disarray = d.disarrayOf(d.align(16, d.vec3f), 3);
|
|
287
|
+
*
|
|
288
|
+
* If `elementCount` is not specified, a partially applied function is returned.
|
|
289
|
+
* @example
|
|
290
|
+
* const disarray = d.disarrayOf(d.vec3f);
|
|
291
|
+
* // ^? (n: number) => Disarray<d.Vec3f>
|
|
292
|
+
*
|
|
293
|
+
* @param elementType The type of elements in the array.
|
|
294
|
+
* @param elementCount The number of elements in the array.
|
|
295
|
+
*/
|
|
296
|
+
const disarrayOf = comptime(((elementType, elementCount) => {
|
|
297
|
+
if (elementCount === void 0) return (count) => cpu_disarrayOf(elementType, count);
|
|
298
|
+
return cpu_disarrayOf(elementType, elementCount);
|
|
299
|
+
})).$name("disarrayOf");
|
|
300
|
+
function cpu_disarrayOf(elementType, elementCount) {
|
|
301
|
+
const disarraySchema = (elements) => {
|
|
302
|
+
if (elements && elements.length !== elementCount) throw new Error(`Disarray schema of ${elementCount} elements of type ${elementType.type} called with ${elements.length} argument(s).`);
|
|
303
|
+
return Array.from({ length: elementCount }, (_, i) => schemaCallWrapper(elementType, elements?.[i]));
|
|
304
|
+
};
|
|
305
|
+
Object.setPrototypeOf(disarraySchema, DisarrayImpl);
|
|
306
|
+
disarraySchema.elementType = elementType;
|
|
307
|
+
if (!Number.isInteger(elementCount) || elementCount < 0) throw new Error(`Cannot create disarray schema with invalid element count: ${elementCount}.`);
|
|
308
|
+
disarraySchema.elementCount = elementCount;
|
|
309
|
+
return disarraySchema;
|
|
310
|
+
}
|
|
311
|
+
const DisarrayImpl = {
|
|
312
|
+
[$internal]: true,
|
|
313
|
+
type: "disarray",
|
|
314
|
+
toString() {
|
|
315
|
+
return `disarrayOf(${this.elementType}, ${this.elementCount})`;
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
//#endregion
|
|
320
|
+
//#region src/data/unstruct.ts
|
|
321
|
+
/**
|
|
322
|
+
* Creates a loose struct schema that can be used to construct vertex buffers.
|
|
323
|
+
* Describes structs with members of both loose and non-loose types.
|
|
324
|
+
*
|
|
325
|
+
* The order of members matches the passed in properties object.
|
|
326
|
+
* Members are not aligned in respect to their `byteAlignment`,
|
|
327
|
+
* unless they are explicitly decorated with the custom align attribute
|
|
328
|
+
* via `d.align` function.
|
|
329
|
+
*
|
|
330
|
+
* @example
|
|
331
|
+
* const CircleStruct = d.unstruct({ radius: d.f32, pos: d.vec3f }); // packed struct with no padding
|
|
332
|
+
*
|
|
333
|
+
* @example
|
|
334
|
+
* const CircleStruct = d.unstruct({ radius: d.f32, pos: d.align(16, d.vec3f) });
|
|
335
|
+
*
|
|
336
|
+
* @param properties Record with `string` keys and `TgpuData` or `TgpuLooseData` values,
|
|
337
|
+
* each entry describing one struct member.
|
|
338
|
+
*/
|
|
339
|
+
function unstruct(properties) {
|
|
340
|
+
const unstructSchema = (instanceProps) => Object.fromEntries(Object.entries(properties).map(([key, schema]) => [key, schemaCallWrapper(schema, instanceProps?.[key])]));
|
|
341
|
+
Object.setPrototypeOf(unstructSchema, UnstructImpl);
|
|
342
|
+
unstructSchema.propTypes = properties;
|
|
343
|
+
return unstructSchema;
|
|
344
|
+
}
|
|
345
|
+
const UnstructImpl = {
|
|
346
|
+
[$internal]: true,
|
|
347
|
+
type: "unstruct",
|
|
348
|
+
$name(label) {
|
|
349
|
+
setName(this, label);
|
|
350
|
+
return this;
|
|
351
|
+
},
|
|
352
|
+
toString() {
|
|
353
|
+
return `unstruct:${getName(this) ?? "<unnamed>"}`;
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
//#endregion
|
|
358
|
+
//#region src/data/deepEqual.ts
|
|
359
|
+
/**
|
|
360
|
+
* Performs a deep comparison of two TypeGPU data schemas.
|
|
361
|
+
*
|
|
362
|
+
* @param a The first data schema to compare.
|
|
363
|
+
* @param b The second data schema to compare.
|
|
364
|
+
* @returns `true` if the schemas are deeply equal, `false` otherwise.
|
|
365
|
+
*
|
|
366
|
+
* @example
|
|
367
|
+
* ```ts
|
|
368
|
+
* import { vec3f, struct, deepEqual } from 'typegpu/data';
|
|
369
|
+
*
|
|
370
|
+
* const schema1 = struct({ a: vec3f });
|
|
371
|
+
* const schema2 = struct({ a: vec3f });
|
|
372
|
+
* const schema3 = struct({ b: vec3f });
|
|
373
|
+
*
|
|
374
|
+
* console.log(deepEqual(schema1, schema2)); // true
|
|
375
|
+
* console.log(deepEqual(schema1, schema3)); // false
|
|
376
|
+
* ```
|
|
377
|
+
*/
|
|
378
|
+
function deepEqual(a, b) {
|
|
379
|
+
if (a === b) return true;
|
|
380
|
+
if (a.type !== b.type) return false;
|
|
381
|
+
if (isWgslStruct(a) && isWgslStruct(b) || isUnstruct(a) && isUnstruct(b)) {
|
|
382
|
+
const aProps = a.propTypes;
|
|
383
|
+
const bProps = b.propTypes;
|
|
384
|
+
const aKeys = Object.keys(aProps);
|
|
385
|
+
const bKeys = Object.keys(bProps);
|
|
386
|
+
if (aKeys.length !== bKeys.length) return false;
|
|
387
|
+
for (let i = 0; i < aKeys.length; i++) {
|
|
388
|
+
const keyA = aKeys[i];
|
|
389
|
+
const keyB = bKeys[i];
|
|
390
|
+
if (keyA !== keyB || !keyA || !keyB || !deepEqual(aProps[keyA], bProps[keyB])) return false;
|
|
391
|
+
}
|
|
392
|
+
return true;
|
|
393
|
+
}
|
|
394
|
+
if (isWgslArray(a) && isWgslArray(b) || isDisarray(a) && isDisarray(b)) return a.elementCount === b.elementCount && deepEqual(a.elementType, b.elementType);
|
|
395
|
+
if (isPtr(a) && isPtr(b)) return a.addressSpace === b.addressSpace && a.access === b.access && deepEqual(a.inner, b.inner);
|
|
396
|
+
if (isAtomic(a) && isAtomic(b)) return deepEqual(a.inner, b.inner);
|
|
397
|
+
if (isDecorated(a) && isDecorated(b) || isLooseDecorated(a) && isLooseDecorated(b)) {
|
|
398
|
+
if (!deepEqual(a.inner, b.inner)) return false;
|
|
399
|
+
if (a.attribs.length !== b.attribs.length) return false;
|
|
400
|
+
const getAttrKey = (attr) => {
|
|
401
|
+
const anyAttr = attr;
|
|
402
|
+
return `${anyAttr.type}(${(anyAttr.params ?? []).join(",")})`;
|
|
403
|
+
};
|
|
404
|
+
const attrsA = a.attribs.map(getAttrKey);
|
|
405
|
+
const attrsB = b.attribs.map(getAttrKey);
|
|
406
|
+
for (let i = 0; i < attrsA.length; i++) if (attrsA[i] !== attrsB[i]) return false;
|
|
407
|
+
}
|
|
408
|
+
return true;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
//#endregion
|
|
412
|
+
export { PUBLIC_getLongestContiguousPrefix as a, offsetsForProps as c, isWgslComparisonSampler as d, isWgslSampler as f, memoryLayoutOf as i, alignIO as l, unstruct as n, PUBLIC_isContiguous as o, sampler as p, disarrayOf as r, atomic as s, deepEqual as t, comparisonSampler as u };
|
|
413
|
+
//# sourceMappingURL=deepEqual-yZXvaV2C.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deepEqual-yZXvaV2C.js","names":[],"sources":["../src/data/sampler.ts","../src/data/alignIO.ts","../src/data/offsets.ts","../src/data/atomic.ts","../src/data/isContiguous.ts","../src/data/getLongestContiguousPrefix.ts","../src/data/offsetUtils.ts","../src/data/disarray.ts","../src/data/unstruct.ts","../src/data/deepEqual.ts"],"sourcesContent":["import { $internal, $repr } from '../shared/symbols.ts';\nimport type { BaseData } from './wgslTypes.ts';\n\nexport interface WgslSamplerProps {\n addressModeU?: GPUAddressMode;\n addressModeV?: GPUAddressMode;\n /**\n * Specifies the address modes for the texture width, height, and depth\n * coordinates, respectively.\n */\n addressModeW?: GPUAddressMode;\n /**\n * Specifies the sampling behavior when the sample footprint is smaller than or equal to one\n * texel.\n */\n magFilter?: GPUFilterMode;\n /**\n * Specifies the sampling behavior when the sample footprint is larger than one texel.\n */\n minFilter?: GPUFilterMode;\n /**\n * Specifies behavior for sampling between mipmap levels.\n */\n mipmapFilter?: GPUMipmapFilterMode;\n lodMinClamp?: number;\n /**\n * Specifies the minimum and maximum levels of detail, respectively, used internally when\n * sampling a texture.\n */\n lodMaxClamp?: number;\n /**\n * Specifies the maximum anisotropy value clamp used by the sampler. Anisotropic filtering is\n * enabled when {@link GPUSamplerDescriptor.maxAnisotropy} is > 1 and the implementation supports it.\n * Anisotropic filtering improves the image quality of textures sampled at oblique viewing\n * angles. Higher {@link GPUSamplerDescriptor.maxAnisotropy} values indicate the maximum ratio of\n * anisotropy supported when filtering.\n *\n * Most implementations support {@link GPUSamplerDescriptor.maxAnisotropy} values in range\n * between 1 and 16, inclusive. The used value of {@link GPUSamplerDescriptor.maxAnisotropy}\n * will be clamped to the maximum value that the platform supports.\n * The precise filtering behavior is implementation-dependent.\n */\n maxAnisotropy?: number;\n}\n\nexport interface WgslComparisonSamplerProps {\n compare: GPUCompareFunction;\n addressModeU?: GPUAddressMode;\n addressModeV?: GPUAddressMode;\n /**\n * Specifies the address modes for the texture width, height, and depth\n * coordinates, respectively.\n */\n addressModeW?: GPUAddressMode;\n /**\n * Specifies the sampling behavior when the sample footprint is smaller than or equal to one\n * texel.\n */\n magFilter?: GPUFilterMode;\n /**\n * Specifies the sampling behavior when the sample footprint is larger than one texel.\n */\n minFilter?: GPUFilterMode;\n /**\n * Specifies behavior for sampling between mipmap levels.\n */\n mipmapFilter?: GPUMipmapFilterMode;\n lodMinClamp?: number;\n /**\n * Specifies the minimum and maximum levels of detail, respectively, used internally when\n * sampling a texture.\n */\n lodMaxClamp?: number;\n /**\n * Specifies the maximum anisotropy value clamp used by the sampler. Anisotropic filtering is\n * enabled when {@link GPUSamplerDescriptor.maxAnisotropy} is > 1 and the implementation supports it.\n * Anisotropic filtering improves the image quality of textures sampled at oblique viewing\n * angles. Higher {@link GPUSamplerDescriptor.maxAnisotropy} values indicate the maximum ratio of\n * anisotropy supported when filtering.\n *\n * Most implementations support {@link GPUSamplerDescriptor.maxAnisotropy} values in range\n * between 1 and 16, inclusive. The used value of {@link GPUSamplerDescriptor.maxAnisotropy}\n * will be clamped to the maximum value that the platform supports.\n * The precise filtering behavior is implementation-dependent.\n */\n maxAnisotropy?: number;\n}\n\nexport interface sampler {\n [$internal]: true;\n type: 'sampler';\n}\n\nexport function sampler(): WgslSampler {\n return {\n [$internal]: {},\n type: 'sampler',\n [$repr]: undefined as unknown as sampler,\n };\n}\n\nexport interface comparisonSampler {\n [$internal]: Record<string, never>;\n type: 'sampler_comparison';\n}\n\nexport function comparisonSampler(): WgslComparisonSampler {\n return {\n [$internal]: {},\n type: 'sampler_comparison',\n [$repr]: undefined as unknown as comparisonSampler,\n };\n}\n\nexport interface WgslSampler extends BaseData {\n readonly [$repr]: sampler;\n readonly type: 'sampler';\n}\n\nexport interface WgslComparisonSampler extends BaseData {\n readonly [$repr]: comparisonSampler;\n readonly type: 'sampler_comparison';\n}\n\nexport function isWgslSampler(value: unknown): value is WgslSampler {\n return (\n !!(value as WgslSampler)[$internal] &&\n (value as WgslSampler).type === 'sampler'\n );\n}\n\nexport function isWgslComparisonSampler(\n value: unknown,\n): value is WgslComparisonSampler {\n return (\n !!(value as WgslComparisonSampler)[$internal] &&\n (value as WgslComparisonSampler).type === 'sampler_comparison'\n );\n}\n","import type { IMeasurer, ISerialInput, ISerialOutput } from 'typed-binary';\n\n/**\n * @param io the IO to align\n * @param baseAlignment must be power of 2\n */\nfunction alignIO(\n io: ISerialInput | ISerialOutput | IMeasurer,\n baseAlignment: number,\n) {\n const currentPos = 'size' in io ? io.size : io.currentByteOffset;\n\n const bitMask = baseAlignment - 1;\n const offset = currentPos & bitMask;\n\n if ('skipBytes' in io) {\n io.skipBytes((baseAlignment - offset) & bitMask);\n } else {\n io.add((baseAlignment - offset) & bitMask);\n }\n}\n\nexport default alignIO;\n","import { Measurer } from 'typed-binary';\nimport { roundUp } from '../mathUtils.ts';\nimport alignIO from './alignIO.ts';\nimport { alignmentOf, customAlignmentOf } from './alignmentOf.ts';\nimport { isUnstruct, type Unstruct } from './dataTypes.ts';\nimport { sizeOf } from './sizeOf.ts';\nimport type { WgslStruct } from './wgslTypes.ts';\n\nexport interface OffsetInfo {\n offset: number;\n size: number;\n padding?: number | undefined;\n}\n\nconst cachedOffsets = new WeakMap<\n WgslStruct | Unstruct,\n Record<string, OffsetInfo>\n>();\n\nexport function offsetsForProps<T extends WgslStruct | Unstruct>(\n struct: T,\n): Record<keyof T['propTypes'], OffsetInfo> {\n type Key = keyof T['propTypes'];\n\n const cached = cachedOffsets.get(struct);\n if (cached) {\n return cached as Record<Key, OffsetInfo>;\n }\n\n const measurer = new Measurer();\n const offsets = {} as Record<Key, OffsetInfo>;\n let lastEntry: OffsetInfo | undefined;\n\n for (const key in struct.propTypes) {\n const prop = struct.propTypes[key];\n if (prop === undefined) {\n throw new Error(`Property ${key} is undefined in struct`);\n }\n\n const beforeAlignment = measurer.size;\n\n alignIO(\n measurer,\n isUnstruct(struct) ? customAlignmentOf(prop) : alignmentOf(prop),\n );\n\n if (lastEntry) {\n lastEntry.padding = measurer.size - beforeAlignment;\n }\n\n const propSize = sizeOf(prop);\n offsets[key as Key] = { offset: measurer.size, size: propSize };\n lastEntry = offsets[key];\n measurer.add(propSize);\n }\n\n if (lastEntry) {\n lastEntry.padding = roundUp(sizeOf(struct), alignmentOf(struct)) -\n measurer.size;\n }\n\n cachedOffsets.set(struct, offsets);\n return offsets;\n}\n","import type { Infer, MemIdentity } from '../shared/repr.ts';\nimport { $internal } from '../shared/symbols.ts';\nimport {\n $gpuRepr,\n $memIdent,\n $repr,\n $validStorageSchema,\n $validUniformSchema,\n $validVertexSchema,\n} from '../shared/symbols.ts';\nimport type { Atomic, atomicI32, atomicU32, I32, U32 } from './wgslTypes.ts';\n\n// ----------\n// Public API\n// ----------\n\n/**\n * Marks a concrete integer scalar type schema (u32 or i32) as a WGSL atomic.\n *\n * @example\n * const atomicU32 = d.atomic(d.u32);\n * const atomicI32 = d.atomic(d.i32);\n *\n * @param data Underlying type schema.\n */\nexport function atomic<TSchema extends U32 | I32>(\n data: TSchema,\n): Atomic<TSchema> {\n return new AtomicImpl(data);\n}\n\n// --------------\n// Implementation\n// --------------\n\nclass AtomicImpl<TSchema extends U32 | I32> implements Atomic<TSchema> {\n public readonly [$internal] = {};\n public readonly type = 'atomic';\n\n // Type-tokens, not available at runtime\n declare readonly [$repr]: Infer<TSchema>;\n declare readonly [$memIdent]: MemIdentity<TSchema>;\n declare readonly [$gpuRepr]: TSchema extends U32 ? atomicU32 : atomicI32;\n declare readonly [$validStorageSchema]: true;\n declare readonly [$validUniformSchema]: true;\n declare readonly [$validVertexSchema]: true;\n // ---\n\n constructor(public readonly inner: TSchema) {}\n}\n","import type { AnyData } from './dataTypes.ts';\nimport type { BaseData } from './wgslTypes.ts';\nimport { getLayoutInfo } from './schemaMemoryLayout.ts';\n\nexport function isContiguous(schema: BaseData): boolean {\n return getLayoutInfo(schema, 'isContiguous');\n}\n\n/**\n * Returns `true` if data represented by the `schema` doesn't have padding.\n */\nexport function PUBLIC_isContiguous(schema: AnyData): boolean {\n return isContiguous(schema);\n}\n","import type { AnyData } from './dataTypes.ts';\nimport type { BaseData } from './wgslTypes.ts';\nimport { getLayoutInfo } from './schemaMemoryLayout.ts';\n\nexport function getLongestContiguousPrefix(schema: BaseData): number {\n return getLayoutInfo(schema, 'longestContiguousPrefix');\n}\n\n/**\n * Returns the size (in bytes) of the longest contiguous memory prefix of data represented by the `schema`.\n */\nexport function PUBLIC_getLongestContiguousPrefix(schema: AnyData): number {\n return getLongestContiguousPrefix(schema);\n}\n","import { roundUp } from '../mathUtils.ts';\nimport { alignmentOf } from './alignmentOf.ts';\nimport {\n type OffsetInfo as PropOffsetInfo,\n offsetsForProps,\n} from './offsets.ts';\nimport { sizeOf } from './sizeOf.ts';\nimport { isContiguous } from './isContiguous.ts';\nimport { getLongestContiguousPrefix } from './getLongestContiguousPrefix.ts';\nimport type {\n AnyWgslData,\n BaseData,\n VecData,\n WgslArray,\n WgslStruct,\n} from './wgslTypes.ts';\nimport { isVec, isWgslArray, isWgslStruct } from './wgslTypes.ts';\nimport { undecorate } from './dataTypes.ts';\nimport type { Infer } from '../shared/repr.ts';\n\nconst OFFSET_MARKER = Symbol('indirectOffset');\nconst CONTIGUOUS_MARKER = Symbol('indirectContiguous');\n\ninterface OffsetProxy {\n [OFFSET_MARKER]: number;\n [CONTIGUOUS_MARKER]: number;\n}\n\nfunction isOffsetProxy(value: unknown): value is OffsetProxy {\n return (\n typeof value === 'object' &&\n value !== null &&\n OFFSET_MARKER in value &&\n CONTIGUOUS_MARKER in value\n );\n}\n\nfunction scalarNode(offset: number, contiguous: number): OffsetProxy {\n return { [OFFSET_MARKER]: offset, [CONTIGUOUS_MARKER]: contiguous };\n}\n\nfunction getMarker(target: OffsetProxy, prop: PropertyKey): number | undefined {\n if (prop === OFFSET_MARKER) {\n return target[OFFSET_MARKER];\n }\n if (prop === CONTIGUOUS_MARKER) {\n return target[CONTIGUOUS_MARKER];\n }\n return undefined;\n}\n\nfunction makeProxy(\n schema: AnyWgslData,\n baseOffset: number,\n contiguous = sizeOf(schema),\n): unknown {\n const unwrapped = undecorate(schema);\n\n const vecComponentCount = isVec(unwrapped)\n ? unwrapped.componentCount\n : undefined;\n\n if (vecComponentCount !== undefined) {\n const componentSize = sizeOf((unwrapped as VecData).primitive);\n return makeVecProxy(\n scalarNode(baseOffset, contiguous),\n componentSize,\n vecComponentCount,\n );\n }\n\n if (isWgslStruct(unwrapped)) {\n return makeStructProxy(unwrapped, scalarNode(baseOffset, contiguous));\n }\n\n if (isWgslArray(unwrapped)) {\n return makeArrayProxy(unwrapped, scalarNode(baseOffset, contiguous));\n }\n\n return scalarNode(baseOffset, contiguous);\n}\n\nexport function createOffsetProxy<T extends BaseData>(\n schema: T,\n baseOffset = 0,\n): unknown {\n return makeProxy(schema as AnyWgslData, baseOffset, sizeOf(schema));\n}\n\nfunction makeVecProxy(\n target: OffsetProxy,\n componentSize: number,\n componentCount: 2 | 3 | 4,\n): unknown {\n const baseOffset = target[OFFSET_MARKER];\n\n return new Proxy(target, {\n get(t, prop) {\n const marker = getMarker(t, prop);\n if (marker !== undefined) {\n return marker;\n }\n\n const idx = prop === 'x' || prop === '0'\n ? 0\n : prop === 'y' || prop === '1'\n ? 1\n : prop === 'z' || prop === '2'\n ? 2\n : prop === 'w' || prop === '3'\n ? 3\n : -1;\n\n if (idx < 0 || idx >= componentCount) {\n return undefined;\n }\n\n const byteOffset = idx * componentSize;\n const contiguous = Math.max(0, t[CONTIGUOUS_MARKER] - byteOffset);\n\n return scalarNode(baseOffset + byteOffset, contiguous);\n },\n });\n}\n\nfunction makeArrayProxy(array: WgslArray, target: OffsetProxy): unknown {\n const elementType = array.elementType as AnyWgslData;\n const elementSize = sizeOf(elementType);\n const stride = roundUp(elementSize, alignmentOf(elementType));\n const hasPadding = stride > elementSize;\n\n return new Proxy(target, {\n get(t, prop) {\n const marker = getMarker(t, prop);\n if (marker !== undefined) {\n return marker;\n }\n\n if (prop === 'length') {\n return array.elementCount;\n }\n\n if (typeof prop !== 'string') {\n return undefined;\n }\n\n const index = Number(prop);\n if (\n !Number.isInteger(index) ||\n index < 0 || index >= array.elementCount\n ) {\n return undefined;\n }\n\n const elementOffset = index * stride;\n const remainingFromHere = !isContiguous(elementType)\n ? elementSize + getLongestContiguousPrefix(elementType) // it is too much, but we correct it later\n : Math.max(\n 0,\n t[CONTIGUOUS_MARKER] - elementOffset,\n );\n\n const childContiguous = hasPadding\n ? Math.min(remainingFromHere, elementSize)\n : remainingFromHere;\n\n return makeProxy(\n elementType,\n t[OFFSET_MARKER] + elementOffset,\n childContiguous,\n );\n },\n });\n}\n\ntype StructFieldMeta = {\n offset: number;\n runEnd: number;\n};\n\nfunction makeStructProxy(struct: WgslStruct, target: OffsetProxy): unknown {\n const offsets = offsetsForProps(struct);\n const propTypes = struct.propTypes as Record<string, AnyWgslData>;\n const propNames = Object.keys(propTypes);\n\n const meta = new Map<string, StructFieldMeta>();\n\n let runStart = 0;\n for (let i = 0; i < propNames.length; i++) {\n const name = propNames[i];\n if (!name) {\n continue;\n }\n const type = propTypes[name];\n if (!type) {\n continue;\n }\n\n const info = offsets[name] as PropOffsetInfo;\n const padding = info.padding ?? 0;\n\n const typeContiguous = isContiguous(type);\n const isRunEnd = i === propNames.length - 1 || padding > 0 ||\n !typeContiguous;\n if (!isRunEnd) {\n continue;\n }\n\n const runEnd = info.offset +\n (typeContiguous ? info.size : getLongestContiguousPrefix(type));\n for (let j = runStart; j <= i; j++) {\n const runName = propNames[j];\n if (!runName) {\n continue;\n }\n const runInfo = offsets[runName] as PropOffsetInfo;\n meta.set(runName, { offset: runInfo.offset, runEnd });\n }\n runStart = i + 1;\n }\n\n return new Proxy(target, {\n get(t, prop) {\n const marker = getMarker(t, prop);\n if (marker !== undefined) {\n return marker;\n }\n\n if (typeof prop !== 'string') {\n return undefined;\n }\n\n const m = meta.get(prop);\n if (!m) {\n return undefined;\n }\n\n const remainingFromHere = Math.max(\n 0,\n t[CONTIGUOUS_MARKER] - m.offset,\n );\n const localLimit = Math.max(0, m.runEnd - m.offset);\n const propSchema = propTypes[prop];\n if (!propSchema) {\n return undefined;\n }\n\n return makeProxy(\n propSchema,\n t[OFFSET_MARKER] + m.offset,\n sizeOf(struct) === m.runEnd ? remainingFromHere : localLimit,\n );\n },\n });\n}\n\nfunction getRootContiguous(schema: AnyWgslData): number {\n const unwrapped = undecorate(schema);\n\n if (isWgslStruct(unwrapped)) {\n const offsets = offsetsForProps(unwrapped);\n const propTypes = unwrapped.propTypes as Record<string, AnyWgslData>;\n const propNames = Object.keys(propTypes);\n\n for (let i = 0; i < propNames.length; i++) {\n const name = propNames[i];\n if (!name) {\n continue;\n }\n const info = offsets[name] as PropOffsetInfo;\n const padding = info.padding ?? 0;\n\n const runEnd = info.offset + info.size;\n const isRunEnd = i === propNames.length - 1 || padding > 0;\n if (isRunEnd) {\n return runEnd;\n }\n }\n\n return 0;\n }\n\n if (isWgslArray(unwrapped)) {\n const elementType = unwrapped.elementType as AnyWgslData;\n const elementSize = sizeOf(elementType);\n const stride = roundUp(elementSize, alignmentOf(elementType));\n const totalSize = sizeOf(schema);\n if (!Number.isFinite(totalSize)) {\n return elementSize;\n }\n return stride > elementSize ? elementSize : totalSize;\n }\n\n return sizeOf(schema);\n}\n\n/**\n * Interface containing information about the offset and the available contiguous after a selected primitive.\n */\nexport interface PrimitiveOffsetInfo {\n /** The byte offset of the primitive within the buffer. */\n offset: number;\n /** The number of contiguous bytes available from the offset. */\n contiguous: number;\n}\n\n/**\n * A function that retrieves offset and information for a specific primitive within a data schema.\n * Example usage:\n * ```ts\n * const Boid = d.struct({\n * position: d.vec3f,\n * velocity: d.vec3f,\n * });\n * const memLayout = d.memoryLayoutOf(Boid, (b) => b.velocity.y);\n * console.log(memLayout.offset); // Byte offset of velocity.y within Boid (here 20 bytes)\n * console.log(memLayout.contiguous); // Contiguous bytes available from that offset (here 8 bytes)\n * ```\n *\n * @param schema - The data schema to analyze.\n * @param accessor - Optional function that accesses a specific primitive within the schema. If omitted, uses the root offset (0).\n * @returns An object containing the offset and contiguous byte information.\n */\nexport function memoryLayoutOf<T extends BaseData>(\n schema: T,\n accessor?: (proxy: Infer<T>) => number,\n): PrimitiveOffsetInfo {\n if (!accessor) {\n return {\n offset: 0,\n contiguous: getRootContiguous(schema as AnyWgslData),\n };\n }\n\n const proxy = createOffsetProxy(schema);\n const result = accessor(proxy as Infer<T>);\n\n if (isOffsetProxy(result)) {\n return {\n offset: result[OFFSET_MARKER],\n contiguous: result[CONTIGUOUS_MARKER],\n };\n }\n\n throw new Error(\n 'Invalid accessor result. Expected an offset proxy with markers.',\n );\n}\n","import { comptime } from '../core/function/comptime.ts';\nimport { $internal } from '../shared/symbols.ts';\nimport type { AnyData, Disarray } from './dataTypes.ts';\nimport { schemaCallWrapper } from './schemaCallWrapper.ts';\n\n// ----------\n// Public API\n// ----------\n\ninterface DisarrayConstructor {\n <TElement extends AnyData>(\n elementType: TElement,\n ): (elementCount: number) => Disarray<TElement>;\n\n <TElement extends AnyData>(\n elementType: TElement,\n elementCount: number,\n ): Disarray<TElement>;\n}\n\n/**\n * Creates an array schema that can be used to construct vertex buffers.\n * Describes arrays with fixed-size length, storing elements of the same type.\n *\n * Elements in the schema are not aligned in respect to their `byteAlignment`,\n * unless they are explicitly decorated with the custom align attribute\n * via `d.align` function.\n *\n * @example\n * const disarray = d.disarrayOf(d.vec3f, 3); // packed array of vec3f\n *\n * @example\n * const disarray = d.disarrayOf(d.align(16, d.vec3f), 3);\n *\n * If `elementCount` is not specified, a partially applied function is returned.\n * @example\n * const disarray = d.disarrayOf(d.vec3f);\n * // ^? (n: number) => Disarray<d.Vec3f>\n *\n * @param elementType The type of elements in the array.\n * @param elementCount The number of elements in the array.\n */\nexport const disarrayOf = comptime(\n ((elementType, elementCount) => {\n if (elementCount === undefined) {\n return (count: number) => cpu_disarrayOf(elementType, count);\n }\n return cpu_disarrayOf(elementType, elementCount);\n }) as DisarrayConstructor,\n).$name('disarrayOf');\n\nexport function cpu_disarrayOf<TElement extends AnyData>(\n elementType: TElement,\n elementCount: number,\n): Disarray<TElement> {\n // In the schema call, create and return a deep copy\n // by wrapping all the values in `elementType` schema calls.\n const disarraySchema = (elements?: TElement[]) => {\n if (elements && elements.length !== elementCount) {\n throw new Error(\n `Disarray schema of ${elementCount} elements of type ${elementType.type} called with ${elements.length} argument(s).`,\n );\n }\n\n return Array.from(\n { length: elementCount },\n (_, i) => schemaCallWrapper(elementType, elements?.[i]),\n );\n };\n Object.setPrototypeOf(disarraySchema, DisarrayImpl);\n\n disarraySchema.elementType = elementType;\n\n if (!Number.isInteger(elementCount) || elementCount < 0) {\n throw new Error(\n `Cannot create disarray schema with invalid element count: ${elementCount}.`,\n );\n }\n disarraySchema.elementCount = elementCount;\n\n return disarraySchema as unknown as Disarray<TElement>;\n}\n\n// --------------\n// Implementation\n// --------------\n\nconst DisarrayImpl = {\n [$internal]: true,\n type: 'disarray',\n\n toString(this: Disarray): string {\n return `disarrayOf(${this.elementType}, ${this.elementCount})`;\n },\n};\n","import { getName, setName } from '../shared/meta.ts';\nimport { $internal } from '../shared/symbols.ts';\nimport type { AnyData, Unstruct } from './dataTypes.ts';\nimport { schemaCallWrapper } from './schemaCallWrapper.ts';\n\n// ----------\n// Public API\n// ----------\n\n/**\n * Creates a loose struct schema that can be used to construct vertex buffers.\n * Describes structs with members of both loose and non-loose types.\n *\n * The order of members matches the passed in properties object.\n * Members are not aligned in respect to their `byteAlignment`,\n * unless they are explicitly decorated with the custom align attribute\n * via `d.align` function.\n *\n * @example\n * const CircleStruct = d.unstruct({ radius: d.f32, pos: d.vec3f }); // packed struct with no padding\n *\n * @example\n * const CircleStruct = d.unstruct({ radius: d.f32, pos: d.align(16, d.vec3f) });\n *\n * @param properties Record with `string` keys and `TgpuData` or `TgpuLooseData` values,\n * each entry describing one struct member.\n */\nexport function unstruct<TProps extends Record<string, AnyData>>(\n properties: TProps,\n): Unstruct<TProps> {\n // In the schema call, create and return a deep copy\n // by wrapping all the values in corresponding schema calls.\n const unstructSchema = (instanceProps?: TProps) =>\n Object.fromEntries(\n Object.entries(properties).map(([key, schema]) => [\n key,\n schemaCallWrapper(schema, instanceProps?.[key]),\n ]),\n );\n Object.setPrototypeOf(unstructSchema, UnstructImpl);\n unstructSchema.propTypes = properties;\n\n return unstructSchema as unknown as Unstruct<TProps>;\n}\n\n// --------------\n// Implementation\n// --------------\n\nconst UnstructImpl = {\n [$internal]: true,\n type: 'unstruct',\n\n $name(label: string) {\n setName(this, label);\n return this;\n },\n\n toString(): string {\n return `unstruct:${getName(this) ?? '<unnamed>'}`;\n },\n};\n","import type { AnyAttribute } from './attributes.ts';\nimport { isDisarray, isLooseDecorated, isUnstruct } from './dataTypes.ts';\nimport type { AnyData } from './dataTypes.ts';\nimport {\n isAtomic,\n isDecorated,\n isPtr,\n isWgslArray,\n isWgslStruct,\n} from './wgslTypes.ts';\n\n/**\n * Performs a deep comparison of two TypeGPU data schemas.\n *\n * @param a The first data schema to compare.\n * @param b The second data schema to compare.\n * @returns `true` if the schemas are deeply equal, `false` otherwise.\n *\n * @example\n * ```ts\n * import { vec3f, struct, deepEqual } from 'typegpu/data';\n *\n * const schema1 = struct({ a: vec3f });\n * const schema2 = struct({ a: vec3f });\n * const schema3 = struct({ b: vec3f });\n *\n * console.log(deepEqual(schema1, schema2)); // true\n * console.log(deepEqual(schema1, schema3)); // false\n * ```\n */\nexport function deepEqual(a: AnyData, b: AnyData): boolean {\n if (a === b) {\n return true;\n }\n\n if (a.type !== b.type) {\n return false;\n }\n\n if (\n (isWgslStruct(a) && isWgslStruct(b)) ||\n (isUnstruct(a) && isUnstruct(b))\n ) {\n const aProps = a.propTypes;\n const bProps = b.propTypes;\n const aKeys = Object.keys(aProps);\n const bKeys = Object.keys(bProps);\n\n if (aKeys.length !== bKeys.length) {\n return false;\n }\n\n for (let i = 0; i < aKeys.length; i++) {\n const keyA = aKeys[i];\n const keyB = bKeys[i];\n if (\n keyA !== keyB || !keyA || !keyB ||\n !deepEqual(aProps[keyA] as AnyData, bProps[keyB] as AnyData)\n ) {\n return false;\n }\n }\n return true;\n }\n\n if ((isWgslArray(a) && isWgslArray(b)) || (isDisarray(a) && isDisarray(b))) {\n return (\n a.elementCount === b.elementCount &&\n deepEqual(a.elementType as AnyData, b.elementType as AnyData)\n );\n }\n\n if (isPtr(a) && isPtr(b)) {\n return (\n a.addressSpace === b.addressSpace &&\n a.access === b.access &&\n deepEqual(a.inner as AnyData, b.inner as AnyData)\n );\n }\n\n if (isAtomic(a) && isAtomic(b)) {\n return deepEqual(a.inner, b.inner);\n }\n\n if (\n (isDecorated(a) && isDecorated(b)) ||\n (isLooseDecorated(a) && isLooseDecorated(b))\n ) {\n if (!deepEqual(a.inner as AnyData, b.inner as AnyData)) {\n return false;\n }\n if (a.attribs.length !== b.attribs.length) {\n return false;\n }\n\n // Create comparable string representations for each attribute\n const getAttrKey = (attr: unknown): string => {\n const anyAttr = attr as AnyAttribute;\n return `${anyAttr.type}(${(anyAttr.params ?? []).join(',')})`;\n };\n\n const attrsA = a.attribs.map(getAttrKey);\n const attrsB = b.attribs.map(getAttrKey);\n\n for (let i = 0; i < attrsA.length; i++) {\n if (attrsA[i] !== attrsB[i]) {\n return false;\n }\n }\n }\n\n // All other types have been checked for equality at the start\n return true;\n}\n"],"mappings":"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"}
|