Operators
wgsl-rs transpiles Rust operators to their WGSL equivalents. Most have a 1:1 mapping.
Arithmetic
| Rust | WGSL | Description |
|---|---|---|
a + b | a + b | addition |
a - b | a - b | subtraction |
a * b | a * b | multiplication |
a / b | a / b | division |
a % b | a % b | remainder |
Comparison
| Rust | WGSL |
|---|---|
a == b | a == b |
a != b | a != b |
a < b | a < b |
a <= b | a <= b |
a > b | a > b |
a >= b | a >= b |
Logical
| Rust | WGSL |
|---|---|
a && b | a && b |
a || b | a || b |
!a | !a |
Bitwise
| Rust | WGSL | Description |
|---|---|---|
a & b | a & b | bitwise and |
a | b | a | b | bitwise or |
a ^ b | a ^ b | bitwise xor |
a << n | a << n | shift left |
a >> n | a >> n | shift right |
&, |, and ^ work on the integer types — i32, u32, and their
vectors (Vec2i/Vec3i/Vec4i and the u equivalents) — with vector
operands applying the operator componentwise. Floating-point and boolean
vectors do not support them. The shifts are currently scalar-only: <<
and >> do not compile on vectors in wgsl-rs, even though the WGSL spec
permits them.
Precedence & Parentheses
Rust and WGSL disagree about the relative precedence of the bitwise and
shift operators versus the comparisons. Rust binds &, ^, |, <<
and >> tighter than ==, !=, <, <=, > and >=; WGSL binds the
comparisons tighter. In Rust, x & mask == flags means
(x & mask) == flags — while the same text in WGSL would mean
x & (mask == flags), which does not even type-check.
To keep the two languages from disagreeing, wgsl-rs emits every binary expression parenthesized, so the generated WGSL always evaluates exactly like the Rust you wrote:
#![allow(unused)]
fn main() {
pub fn hit(x: u32) -> bool {
x & 3 == 3
}
}
fn hit(x: u32) -> bool {
return ((x & 3) == 3);
}
Explicit grouping is preserved — for integer operands, !(a & b) renders as ~(a & b), while the parentheses remain around a & b. For boolean expressions, ! remains WGSL’s logical-not operator.
Generated WGSL may contain visually redundant parentheses ((a + b) where a + b would do). That is harmless: it guarantees your expression structure survives WGSL’s precedence rules exactly as you wrote it in Rust. See
issue #159 for the
original report.
Compound Assignment
+=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>= all transpile directly:
#![allow(unused)]
fn main() {
pub fn bump(x: ptr!(function, f32)) {
*x += 1.0;
*x *= 2.0;
}
}
Mutable references in function signatures must use the
ptr!macro — bare&mut Tparameters are not supported in#[wgsl]modules.
select
select(false_val, true_val, condition) maps to the WGSL select builtin. Argument order matches WGSL:
#![allow(unused)]
fn main() {
pub fn abs_or(x: f32, sign: bool) -> f32 {
select(-x, x, sign)
}
}
fn abs_or(x: f32, sign: bool) -> f32 {
return select(-x, x, sign);
}
Unary
| Rust | WGSL | Description |
|---|---|---|
-a | -a | negation |
!a | !a | logical/bitwise not |
*p | *p | dereference (for ptr!) |
as Casts
as casts are transpiled when meaningful in WGSL. The common case is as usize for array indexing — this is stripped in WGSL, which uses the index directly:
#![allow(unused)]
fn main() {
pub fn at(arr: Vec4f, i: u32) -> f32 {
arr[i as usize]
}
}
fn at(arr: vec4<f32>, i: u32) -> f32 {
return arr[i];
}