2024-04-25 01:41:47 +01:00
|
|
|
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 {
|
2024-08-28 02:35:53 +01:00
|
|
|
const Tag = @typeInfo(AnySlice).@"union".tag_type.?;
|
|
|
|
inline for (@typeInfo(Tag).@"enum".fields) |field| {
|
2024-04-25 01:41:47 +01:00
|
|
|
// 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
|