1const std = @import("std");
2const expectEqual = std.testing.expectEqual;
3
4const SliceTypeA = extern struct {
5 len: usize,
6 ptr: [*]u32,
7};
8const SliceTypeB = extern struct {
9 ptr: [*]SliceTypeA,
10 len: usize,
11};
12const AnySlice = union(enum(u8)) {
13 a: SliceTypeA,
14 b: SliceTypeB,
15 c: []const u8,
16 d: []AnySlice,
17};
18
19fn withFor(any: AnySlice) usize {
20 const Tag = @typeInfo(AnySlice).@"union".tag_type.?;
21 const info = @typeInfo(Tag).@"enum";
22 inline for (info.field_names, info.field_values) |field_name, field_value| {
23 // With `inline for` the function gets generated as
24 // a series of `if` statements relying on the optimizer
25 // to convert it to a switch.
26 if (field_value == @backingInt(any)) {
27 return @field(any, field_name).len;
28 }
29 }
30 // When using `inline for` the compiler doesn't know that every
31 // possible case has been handled requiring an explicit `unreachable`.
32 unreachable;
33}
34
35fn withSwitch(any: AnySlice) usize {
36 return switch (any) {
37 // With `inline else` the function is explicitly generated
38 // as the desired switch and the compiler can check that
39 // every possible case is handled.
40 inline else => |slice| slice.len,
41 };
42}
43
44test "inline for and inline else similarity" {
45 const any = AnySlice{ .c = "hello" };
46 try expectEqual(5, withFor(any));
47 try expectEqual(5, withSwitch(any));
48}
49
50// test