But this would require the source elements to already be in a tuple (or struct) to fill in t1, no?
(The code below doesn’t compile. ) I haven’t quite gotten this to work, but I think it’s closer to what you need (and, eerily close to std.meta.Tuple(), though that only creates a tuple with the requires types?):
const std = @import("std");
fn itoa(comptime value: anytype) [:0]const u8 {
comptime var s: [:0]const u8 = "";
comptime var n = value;
if (n == 0) {
s = s ++ .{'0'};
} else {
while (n != 0) {
s = s ++ .{'0' + (n % 10)};
n = n / 10;
}
}
return s;
}
fn tuplify(comptime fields: anytype) type {
comptime var tuple_fields: []const std.builtin.Type.StructField = &.{};
inline for (&fields) |*f| {
const T = @TypeOf(f);
const field: std.builtin.Type.StructField = .{
.name = itoa(tuple_fields.len),
.type = @TypeOf(T),
.default_value = @as(?*const anyopaque, @ptrCast(@alignCast(@constCast(f)))),
.is_comptime = true,
.alignment = if (@sizeOf(T) > 0) @alignOf(T) else 0,
};
tuple_fields = tuple_fields ++ &[1]std.builtin.Type.StructField{field};
}
return @Type(.{
.@"struct" = .{
.is_tuple = true,
.layout = .auto,
.decls = &.{},
.fields = tuple_fields,
},
});
}
pub fn main() !void {
const t = tuplify(.{ 92, "walrus", false }){};
std.debug.print("t: {any}\n", .{t});
}
In short, set up the anonymous struct, mark it as a tuple, give each new field a name that corresponds to the index, and add the StructFields one by one in a loop, then reify it at the end with @Type(). The default_value fields should make sure that default-initializing the tuple so constructed fills it with the right values.
However, this gives me the following error:
main.zig:34:12: error: comptime dereference requires 'type' to have a well-defined layout
return @Type(.{
^~~~~
Note that the init_val is necessary due to a minor compiler bug which writing const ptr: *const anyopaque = &.{} exposes (although perhaps it’s good for that to not work…).