schell / schell/wgsl-rs

Support pattern matching (destructuring) in let bindings

Open
#91 0 comments 0 reactions 0 assignees View on GitHub
enhancement
Dominant language
Rust
Stars
61
Forks
4
Avg merge
1d 21h
Merged PRs (30d)
9

Description

## Summary

Support struct destructuring patterns in `let` bindings within `#[wgsl]` modules. Since WGSL has no native destructuring syntax, the proc macro should desugar patterns into a series of individual `let` (or `var`) bindings that access each field.

## Motivation

Currently, attempting to destructure a struct in a let binding:

```rust
let MyStruct { x, y } = some_expr;
```

produces the error: `"Unsupported pattern in let binding: '...'"` (from `parse.rs` line ~1856). Users coming from Rust expect destructuring to work, and desugaring it is straightforward since WGSL supports field access.

## Proposed Behavior

A destructuring let binding like:

```rust
let MyStruct { x, y, z } = compute_point();
```

would expand to WGSL equivalent of:

```wgsl
let _tmp = compute_point();
let x = _tmp.x;
let y = _tmp.y;
let z = _tmp.z;
```

### Mutable destructuring

```rust
let mut MyStruct { x, y } = some_expr;
```

would expand to:

```wgsl
let _tmp = some_expr;
var x = _tmp.x;
var y = _tmp.y;
```

### Field renaming

```rust
let MyStruct { x: px, y: py } = some_expr;
```

would expand to:

```wgsl
let _tmp = some_expr;
let px = _tmp.x;
let py = _tmp.y;
```

### Nested destructuring (stretch goal)

```rust
let Outer { inner: Inner { a, b }, c } = expr;
```

could expand to:

```wgsl
let _tmp = expr;
let _tmp_inner = _tmp.inner;
let a = _tmp_inner.a;
let b = _tmp_inner.b;
let c = _tmp.c;
```

## Implementation Notes

The key code locations are:

- **Parsing**: `crates/wgsl-rs-macros/src/parse.rs` ~line 1816 — the `ident_mut_ty` function inside `TryFrom<&syn::Local> for Local` currently only handles `Pat::Ident` and `Pat::Type`. Would need to handle `Pat::Struct` (and potentially `Pat::Tuple` for tuple-like access).

- **AST**: The `Local` struct (`parse.rs` ~line 1796) holds a single `ident`. Two possible approaches:
1. **Desugar during parsing**: Convert a destructuring `syn::Local` into multiple `Stmt::Local` nodes in the AST, so code generation stays unchanged.
2. **Expand during code gen**: Add a new `Stmt` variant (e.g., `Stmt::Destructure`) and expand it in `formatter.rs`.

Option 1 (desugar during parsing) is likely simpler and keeps the `Local` type and code gen untouched.

- **Code gen**: `crates/wgsl-rs-macros/src/code_gen/formatter.rs` ~line 990 — `GenerateCode for Local`. If desugaring happens at parse time, no changes needed here.

- **Temp variable naming**: The generated temporary variable (e.g., `_tmp`) must use a unique/hygienic name to avoid collisions. A counter or span-based naming scheme could work.

## Scope

- **In scope**: Struct field destructuring (`Pat::Struct`), field renaming, mutable bindings
- **Stretch**: Nested destructuring, partial destructuring with `..` (rest pattern)
- **Out of scope**: Tuple destructuring (WGSL doesn't have tuples), refutable patterns, let-else

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.