Skip to content

Instantly share code, notes, and snippets.

@tauoverpi
Last active September 2, 2023 00:18
Show Gist options
  • Save tauoverpi/360f32c98b8061f2ab884517218245d7 to your computer and use it in GitHub Desktop.
Save tauoverpi/360f32c98b8061f2ab884517218245d7 to your computer and use it in GitHub Desktop.
Comptime is a trap
pub fn dispatch(arena: Allocator, cwd: Dir, context: Context, argv: []const [*:0]const u8, comptime hooks: Self) !void {
const basename = fs.path.basename(mem.span(argv[0]));
const command = Self.map.get(basename) orelse return error.UnknownCommand;
switch (command) {
inline else => |tag| {
const com = @field(hooks, @tagName(tag));
const Fn = @TypeOf(com);
const info = @typeInfo(Fn).Fn;
var tuple: meta.ArgsTuple(Fn) = undefined;
tuple[0] = arena;
tuple[1] = context;
var range: usize = 0;
defer inline for (info.params[2..], 2..) |param, index| {
switch (param.type.?) {
File => if (index < range) tuple[index].close(),
else => {},
}
};
inline for (info.params[2..], 1..) |param, index| {
range += 1;
const T = param.type.?;
if (@typeInfo(T) != .Optional and index >= argv.len) {
return error.TooFewArgs;
}
const value = switch (@typeInfo(T)) {
.Int => try std.fmt.parseInt(T, mem.span(argv[index]), 10),
.Optional => |opt| if (index < argv.len) switch (opt.child) {
Self.Source => blk: {
const source = std.meta.stringToEnum(Self.Source.Tag, mem.span(argv[index])) orelse
return error.InvalidSource;
break :blk switch (source) {
.commit => if (index + 1 >= argv.len)
return error.MissingArgument
else
@as(Self.Source, .{ .commit = mem.span(argv[index + 1]) }),
inline else => |name| @unionInit(Self.Source, @tagName(name), {}),
};
},
[]const u8 => mem.span(argv[index]),
else => @compileError(@typeName(T) ++ " is not supported for optional arguments"),
} else null,
else => switch (T) {
File => try cwd.openFile(mem.span(argv[index]), .{ .mode = .read_write }),
Self.Command => meta.stringToEnum(Self.Command, mem.span(argv[index])) orelse return error.InvalidCommand,
Self.Status => meta.stringToEnum(Self.Status, mem.span(argv[index])) orelse return error.InvalidStatus,
Self.State => meta.stringToEnum(Self.State, mem.span(argv[index])) orelse return error.InvalidState,
Self.Type => meta.stringToEnum(Self.Type, mem.span(argv[index])) orelse return error.InvalidType,
[]const u8 => mem.span(argv[index]),
[]const [*:0]const u8 => argv[1..],
else => @compileError(@typeName(T) ++ " is not supported for regular arguments"),
},
};
tuple[index + 1] = value;
}
try @call(.auto, com, tuple);
},
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment