I’m using metaprogramming to construct a tagged union in comptime.
Since I know the number of fields in advance, I’m assembling them as an array, thinking this would be more performant than constructing a slice.
However, when I use & to convert the array into a slice, I feel uneasy, as this inevitably leads to dangling pointers. Even though this is comptime, I’m still unsure if this is safe.
...
const supported_capacity_log2_min = 5;
const supported_capacity_log2_max = 20;
const Dispatcher = comptime blk: {
var union_fields: [supported_capacity_log2_max - supported_capacity_log2_min + 1]std.builtin.Type.UnionField = undefined;
var enum_fields: [supported_capacity_log2_max - supported_capacity_log2_min + 1]std.builtin.Type.EnumField = undefined;
for (supported_capacity_log2_min..supported_capacity_log2_max + 1, 0..) |capacity_log2, i| {
const tag_name = std.fmt.comptimePrint("q{d}", .{1 << capacity_log2});
const FieldType = *MpscQueue(T, capacity_log2, SequenceTypeOverride);
const new_union_field: std.builtin.Type.UnionField = .{
.name = tag_name,
.type = FieldType,
.alignment = @alignOf(FieldType),
};
const new_enum_field: std.builtin.Type.EnumField = .{
.name = tag_name,
.value = capacity_log2,
};
union_fields[i] = new_union_field;
enum_fields[i] = new_enum_field;
}
const TagType = @Type(.{ .@"enum" = .{
.tag_type = std.math.IntFittingRange(supported_capacity_log2_min, supported_capacity_log2_max),
.fields = &enum_fields,
.decls = &.{},
.is_exhaustive = true,
} });
break :blk @Type(.{ .@"union" = .{
.layout = .auto,
.tag_type = TagType,
.fields = &union_fields,
.decls = &.{},
} });
};
...