2024-04-25 01:41:47 +01:00
|
|
|
const std = @import("std");
|
|
|
|
const expect = std.testing.expect;
|
|
|
|
const expectError = std.testing.expectError;
|
|
|
|
|
|
|
|
fn isFieldOptional(comptime T: type, field_index: usize) !bool {
|
2024-08-28 02:35:53 +01:00
|
|
|
const fields = @typeInfo(T).@"struct".fields;
|
2024-04-25 01:41:47 +01:00
|
|
|
return switch (field_index) {
|
|
|
|
// This prong is analyzed twice with `idx` being a
|
|
|
|
// comptime-known value each time.
|
2024-08-28 02:35:53 +01:00
|
|
|
inline 0, 1 => |idx| @typeInfo(fields[idx].type) == .optional,
|
2024-04-25 01:41:47 +01:00
|
|
|
else => return error.IndexOutOfBounds,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
const Struct1 = struct { a: u32, b: ?u32 };
|
|
|
|
|
|
|
|
test "using @typeInfo with runtime values" {
|
|
|
|
var index: usize = 0;
|
|
|
|
try expect(!try isFieldOptional(Struct1, index));
|
|
|
|
index += 1;
|
|
|
|
try expect(try isFieldOptional(Struct1, index));
|
|
|
|
index += 1;
|
|
|
|
try expectError(error.IndexOutOfBounds, isFieldOptional(Struct1, index));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Calls to `isFieldOptional` on `Struct1` get unrolled to an equivalent
|
|
|
|
// of this function:
|
|
|
|
fn isFieldOptionalUnrolled(field_index: usize) !bool {
|
|
|
|
return switch (field_index) {
|
|
|
|
0 => false,
|
|
|
|
1 => true,
|
|
|
|
else => return error.IndexOutOfBounds,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
// test
|