Enums
Algebraic data types with variants, pattern matching, and compile-time methods.
Turn the guide into code
Take the key idea from this page into the playground and validate it in a real shader instead of leaving it as theory.
Open PlaygroundBWSL enums cover both plain named values and payload-carrying sum types. They also support eval methods and bitflag-style usage.
Basic Enums
At their simplest, enums define a set of named variants:
enum RenderMode {
Forward,
Deferred,
RayTraced
}
Variants with Associated Data
Enum variants can carry associated data:
enum SDFShape {
Sphere(float radius),
Box(float3 size),
Torus(float major, float minor)
}
SDFShape sphere = SDFShape::Sphere(1.0);
SDFShape box = SDFShape::Box(float3(1.0, 2.0, 1.0));
SDFShape torus = SDFShape::Torus(2.0, 0.5);
Eval Methods
Enums can define eval methods that pattern match on the current variant. The parameter list does not declare self; self is implicit inside the body.
enum SDFShape {
Sphere(float radius),
Box(float3 size),
Torus(float major, float minor),
eval distance :: (float3 p) -> float {
Sphere(r): length(p) - r
Box(size): {
float3 d = abs(p) - size;
float outside = length(max(d, 0.0));
float inside = min(max(d.x, max(d.y, d.z)), 0.0);
return outside + inside;
}
Torus(major, minor): {
float2 q = float2(length(p.xz) - major, p.y);
return length(q) - minor;
}
}
eval normal :: (float3 p, float eps) -> float3 {
float d = self.distance(p);
return normalize(float3(
self.distance(p + float3(eps, 0.0, 0.0)) - d,
self.distance(p + float3(0.0, eps, 0.0)) - d,
self.distance(p + float3(0.0, 0.0, eps)) - d
));
}
}
Method Syntax
evalmarks the method for compile-time evaluationselfrefers to the enum instance and is available implicitly- Pattern arms use
VariantName(bindings): expressionsyntax - Multi-statement arms use braces:
VariantName(bindings): { ... }
Pattern Matching in Functions
Pattern matching also works outside enum definitions:
shapeDistance :: (SDFShape shape, float3 p) -> float {
Sphere(r): length(p) - r
Box(size): {
float3 d = abs(p) - size;
return length(max(d, 0.0));
}
Torus(major, minor): {
float2 q = float2(length(p.xz) - major, p.y);
return length(q) - minor;
}
}
Default Arms
Use default to handle multiple variants with a single arm:
enum ShaderValue {
Constant(float4),
Generated,
Computed,
eval isStatic :: () -> bool {
Constant(_): true
default: false
}
}
The _ wildcard ignores the associated data.
Typed Enums and Bitflags
Enums can specify an underlying integer type and explicit values:
enum Channels : uint {
Red = 0b0001,
Green = 0b0010,
Blue = 0b0100,
Alpha = 0b1000,
eval has :: (Channels flag) -> bool {
return (self & flag) != 0;
}
}
Channels mask = Channels::Red | Channels::Blue;
bool hasRed = mask.has(Channels::Red);
Supported Underlying Types
| Type | Description |
|---|---|
int | Signed integer-backed enum |
uint | Unsigned integer-backed enum |
Complex Example
enum Light {
Point(float3 position, float radius),
Directional(float3 direction),
eval directionTo :: (float3 surfacePos) -> float3 {
Point(pos, _): normalize(pos - surfacePos)
Directional(dir): -dir
}
eval intensityAt :: (float3 surfacePos) -> float {
Point(pos, radius): {
float dist = distance(pos, surfacePos);
return saturate(1.0 - dist / radius);
}
Directional(_): 1.0
}
}
When the enum variant is known at compile time, eval methods are fully evaluated and inlined, resulting in zero runtime overhead.
See Also
- Eval - Compile-time evaluation and code folding
- Types Overview - All BWSL types