Hello,
I was wondering how to make the following return a generic tuple.
I have all the information I need at comptime, how long the return tuple should be (as long as the possibleArgs array)
and which type is on which position (the type of the DefaultValue). But I just don’t know how to set it up.
const String = []const u8;
const DefaultValue = union(enum) {
number: i32,
boolean: bool,
string: String,
};
const Arg = struct { String, DefaultValue };
pub fn parseArgs(comptime possibleArgs: []const Arg, args: []const String) struct { String, bool } {
const short1, const defaultValue1 = possibleArgs[0];
const short2, const defaultValue2 = possibleArgs[1];
const value1 = switch (defaultValue1) {
.string => |str| parseStringArg(short1, str, args),
else => unreachable,
};
const value2 = switch (defaultValue2) {
.boolean => |bl| parseBoolArg(short2, bl, args),
else => unreachable,
};
return .{
value1,
value2,
};
}
Any help and suggestions are appreciated.
To give you some pointers in the right direction:
- You can call a function to compute the return type like this:
fn ParseArgsType(...) type {...}
pub fn parseArgs(comptime possibleArgs...) ParseArgsType(possibleArgs) {...}
- You can use the
@Type
builtin function to create a generic type, such as a tuple, at compile time. It takes the same data structure that you also get when calling @typeInfo
, so you can test around with some example tuples for @typeInfo
to figure out what you need.
1 Like
Thanks for all your help, much appreciated.
This is the solution I went with:
pub fn parseArgs(comptime possibleArgs: []const Arg, args: []const []const u8, allocator: Allocator) !ParseArgsType(possibleArgs) {
var result: ParseArgsType(possibleArgs) = undefined;
inline for (possibleArgs, 0..) |arg, i| {
const short, const long, const defaultValue = arg;
const field_name = comptime std.fmt.comptimePrint("{}", .{i});
@field(result, field_name) = switch (defaultValue) {
.string => |str| parseStringArg(short, long, str, args, allocator),
.boolean => |bl| parseBoolArg(short, long, bl, args, allocator),
};
}
return result;
}
fn ParseArgsType(comptime possibleArgs: []const Arg) type {
const fields = comptime blk: {
var result: [possibleArgs.len]std.builtin.Type.StructField = undefined;
for (possibleArgs, 0..) |item, i| {
const theType = switch (item[2]) {
.string => |str| @TypeOf(str),
.boolean => |bl| @TypeOf(bl),
};
result[i] = .{
.name = std.fmt.comptimePrint("{d}", .{i}),
.type = theType,
.default_value = null,
.is_comptime = false,
.alignment = @alignOf(theType),
};
}
break :blk result;
};
return @Type(.{
.Struct = .{
.layout = .auto,
.fields = &fields,
.decls = &.{},
.is_tuple = true,
},
});
}