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

Structs, Impls, and Enums

Structs

Structs are declared with public fields:

#![allow(unused)]
fn main() {
#[wgsl]
pub mod types {
    use wgsl_rs::std::*;

    pub struct Light {
        pub position: Vec3f,
        pub color: Vec3f,
        pub intensity: f32,
    }
}
}

Transpiles to:

struct Light {
  position: vec3<f32>,
  color: vec3<f32>,
  intensity: f32,
}

#[derive(Wgsl)]

Structs used in storage or uniform buffers should derive Wgsl. This generates the host-side layout and zero-value logic needed for binding setup:

#![allow(unused)]
fn main() {
#[derive(Wgsl)]
pub struct Camera {
    pub view: Mat4f,
    pub proj: Mat4f,
    pub pos: Vec3f,
}
}

Inherent Impls

Methods in impl Type blocks become free WGSL functions named Type_method:

#![allow(unused)]
fn main() {
impl Light {
    pub fn direction(self: Light, target: Vec3f) -> Vec3f {
        normalize(target - self.position)
    }
}
}

In Rust you call Light::direction(light, target). In WGSL this becomes:

fn Light_direction(self_1: Light, target: vec3<f32>) -> vec3<f32> {
  return normalize(target - self_1.position);
}

Associated Constants

const items inside an impl block become associated constants in WGSL:

#![allow(unused)]
fn main() {
impl Light {
    pub const MAX_COUNT: u32 = 64;
}
}

Trait Impls

Trait definitions are Rust-only (the trait is not emitted to WGSL), but the methods in a trait impl are transpiled as if they were inherent methods. This lets you share method syntax between CPU and GPU code:

#![allow(unused)]
fn main() {
pub trait Packed {
    fn pack(self) -> u32;
}

impl Packed for Vec4f {
    pub fn pack(self) -> u32 {
        // bit-packing logic
        0u32
    }
}
}

The pack method transpiles to Vec4f_pack.

Non-pub items in trait impls

Rust forbids pub on any item inside a trait impl (E0449), so wgsl-rs does not require pub on trait-impl methods or associated constants — only inherent impl blocks require pub. This matches Rust's own visibility rules:

#![allow(unused)]
fn main() {
pub trait SlabItem {
    const SLAB_SIZE: usize;
    fn read_at(slab_index: u32) -> Self;
}

impl SlabItem for u32 {
    const SLAB_SIZE: usize = 1;  // no `pub` — correct for a trait impl
    fn read_at(slab_index: u32) -> u32 {
        slab_index
    }
}
}

The associated const is mangled to u32__1SLAB_SIZE in WGSL (the _1 escapes the underscore in SLAB_SIZE per the bijective mangling scheme).

Associated Types in Trait Impls

Trait impls may include associated type definitions (type Array = ...;). The concrete type is resolved at monomorphization time and emitted as a WGSL alias:

#![allow(unused)]
fn main() {
pub trait SlabItem {
    const SLAB_SIZE: usize;
    type Array: Default;
    fn to_array(data: Self) -> Self::Array;
    fn from_array(arr: Self::Array) -> Self;
}

impl SlabItem for u32 {
    const SLAB_SIZE: usize = 1;
    type Array = [u32; 1];
    fn to_array(data: Self) -> Self::Array {
        [data]
    }
    fn from_array(arr: Self::Array) -> Self {
        arr[0]
    }
}
}

This produces:

alias u32_Array = array<u32, 1>;

fn u32__1to_array(data: u32) -> array<u32, 1> {
    return array(data);
}

fn u32__1from_array(arr: array<u32, 1>) -> u32 {
    return arr[0];
}

Self::Array in method signatures is resolved to the concrete type ([u32; 1]array<u32, 1>) before rendering.

Enums

#[repr(u32)] enums with explicit discriminants transpile to a u32 alias plus const variants:

#![allow(unused)]
fn main() {
#[repr(u32)]
pub enum Mode {
    Add = 0,
    Multiply = 1,
    Screen = 2,
}
}
alias Mode = u32;
const Add: Mode = 0;
const Multiply: Mode = 1;
const Screen: Mode = 2;

Enums are used with match (see Control Flow), which transpiles to a WGSL switch.