OK, here is another one. I’m building a “parallel” operator, which basically concats inputs and outputs from two blocks. It works as expected, but I have to manage the case where I’m merging two structs with fields having the same name.
At first, I tried something like this:
comptime var input_fields = std.meta.fields(A.Input) ++ std.meta.fields(A.Output);
input_fields[0].name = input_fields[0].name ++ ".a"; // actually in a for loop
But the compiler yelled at me because I can’t modify .name
because it is declared const
. So instead I had to rebuild a list of fields, like this.
fn Par(comptime A: type, comptime B: type) type {
// input fields
const input_a = std.meta.fields(A.Input);
const input_b = std.meta.fields(B.Input);
comptime var input_fields: [input_a.len + input_b.len]builtin.Type.StructField = undefined;
for (input_a, 0..) |f, i| {
input_fields[i] = .{
.name = f.name ++ ".a",
.type = f.type,
.default_value = f.default_value,
.is_comptime = f.is_comptime,
.alignment = f.alignment,
};
}
for (input_b, input_a.len..) |f, i| {
input_fields[i] = .{
.name = f.name ++ ".b",
.type = f.type,
.default_value = f.default_value,
.is_comptime = f.is_comptime,
.alignment = f.alignment,
};
}
// output fields
const output_a = std.meta.fields(A.Output);
const output_b = std.meta.fields(B.Output);
comptime var output_fields: [output_a.len + output_b.len]builtin.Type.StructField = undefined;
for (output_a, 0..) |f, i| {
output_fields[i] = .{
.name = f.name ++ ".a",
.type = f.type,
.default_value = f.default_value,
.is_comptime = f.is_comptime,
.alignment = f.alignment,
};
}
for (output_b, output_a.len..) |f, i| {
output_fields[i] = .{
.name = f.name ++ ".b",
.type = f.type,
.default_value = f.default_value,
.is_comptime = f.is_comptime,
.alignment = f.alignment,
};
}
return struct {
a: A = A{},
b: B = B{},
pub const Input = @Type(.{
.Struct = .{
.layout = .Auto,
.fields = &input_fields,
.decls = &[_]builtin.Type.Declaration{},
.is_tuple = false,
},
});
pub const Output = @Type(.{
.Struct = .{
.layout = .Auto,
.fields = &output_fields,
.decls = &[_]builtin.Type.Declaration{},
.is_tuple = false,
},
});
const Self = @This();
fn eval(self: *Self, input: Self.Input) Self.Output {
_ = input;
_ = self;
// TODO
}
};
}
Am I overcomplicating things? Is there a way to patch that field name in place?