Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Operators

wgsl-rs transpiles Rust operators to their WGSL equivalents. Most have a 1:1 mapping.

Arithmetic

RustWGSLDescription
a + ba + baddition
a - ba - bsubtraction
a * ba * bmultiplication
a / ba / bdivision
a % ba % bremainder

Comparison

RustWGSL
a == ba == b
a != ba != b
a < ba < b
a <= ba <= b
a > ba > b
a >= ba >= b

Logical

RustWGSL
a && ba && b
a || ba || b
!a!a

Bitwise

RustWGSLDescription
a & ba & bbitwise and
a | ba | bbitwise or
a ^ ba ^ bbitwise xor
a << na << nshift left
a >> na >> nshift 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 T parameters 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

RustWGSLDescription
-a-anegation
!a!alogical/bitwise not
*p*pdereference (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];
}