const std = @import("std"); const expect = std.testing.expect; const SliceTypeA = extern struct { len: usize, ptr: [*]u32, }; const SliceTypeB = extern struct { ptr: [*]SliceTypeA, len: usize, }; const AnySlice = union(enum) { a: SliceTypeA, b: SliceTypeB, c: []const u8, d: []AnySlice, }; fn withFor(any: AnySlice) usize { const Tag = @typeInfo(AnySlice).@"union".tag_type.?; inline for (@typeInfo(Tag).@"enum".fields) |field| { // With `inline for` the function gets generated as // a series of `if` statements relying on the optimizer // to convert it to a switch. if (field.value == @intFromEnum(any)) { return @field(any, field.name).len; } } // When using `inline for` the compiler doesn't know that every // possible case has been handled requiring an explicit `unreachable`. unreachable; } fn withSwitch(any: AnySlice) usize { return switch (any) { // With `inline else` the function is explicitly generated // as the desired switch and the compiler can check that // every possible case is handled. inline else => |slice| slice.len, }; } test "inline for and inline else similarity" { const any = AnySlice{ .c = "hello" }; try expect(withFor(any) == 5); try expect(withSwitch(any) == 5); } // test