Pimp My IDE / garage dispatchBack to dispatches
WebGPU / host memory / 30 SEP 2026

Measure the bytes before the GPU does.

A Rust struct and a WGSL struct can share field names and disagree about where the fields live. Put their offsets on the same rail. Fail the build before a bad buffer becomes a reboot.

The bug hides in familiar syntax

Same fields. Different byte map.

Matt Keeter posted a compact WebGPU failure that deserves a place in every graphics build. A Rust [[f32; 3]; 3] occupies 36 tightly packed bytes. WGSL gives mat3x3f a size of 48 bytes and an alignment of 16. The next field begins at byte 48 in the shader, not byte 36.

The compiler can accept both types. The host can write the buffer. The shader can read it. None of those facts proves that both sides agree on the map.

Keeter's repair parses the WGSL with Naga and compares its structure metadata with Rust offsets. Facet supplies runtime type information for the Rust side. The Facet derive is enabled only in tests, so the shipping struct does not need reflection support.

Treat a shared buffer layout as a contract between two type systems. Test the contract at the byte boundary.
01 / PARSE

Read the shader type

Parse the WGSL source and find the exact structure by name.

02 / REFLECT

Read the host type

Collect Rust field names, offsets, alignment, and total size from one reflected type.

03 / COMPARE

Match every member

Fail on a missing field or a different offset. Do not stop at matching names.

04 / SPAN

Check the total span

Compare full size too. Handle a final runtime-sized array as an explicit case.

Interactive makeover / GPU layout witness jig

Put both byte maps on one datum

A hex dump makes the mismatch hard to see. This jig puts host and shader spans on one scale, then builds an ordered test card. It teaches known examples. It does not inspect your source or run a GPU test.

PARSEREFLECTCOMPARESPAN

Choose the specimen

Switch between a clean fit and two layouts whose array or matrix stride differs.

Known layout example
Test-card sections
LAYOUT MISMATCH VISIBLE0 sections selected

The shader moves the next field.

The sample mismatch is known. Select the test sections to draft a check for your own type.

The practical build rule

Make the mismatch boring

The WGSL specification defines alignment and size separately. A three-component float vector has a size of 12 bytes and an alignment of 16. An array rounds each element up to its alignment, so two vec3f values consume 32 bytes. Two Rust [f32; 3] values normally consume 24.

That is why one hand-written assertion is not enough. A generic checker should compare every field and the total span. It should fail when either side gains a field. A final runtime-sized array needs its own rule because the shader structure has no fixed final length.

Keep the test beside the buffer-writing code. Feed it the shader source used by the build. Run it in continuous integration. If generated bindings already own this contract, test the generated result instead of building a second source of truth.