The user can provide a context type and corresponding value that will get passed into any executed callbacks. This allows for complex behavior through side effects and provides a mechanism by which the user can pass an allocator into argument handlers, etc. There was also a lot of restructuring in this including a bit more automagical behavior, like making parameters that wrap optional types default to being optional. The start of automatic handler picking (user overridable, of course) is in place as well. Needing to specify the userdata context type makes things a bit more verbose, and there's some other jank I'm interested in trying to remove. I have some ideas, but I don't know how far I can go in my abuse of the compiler. However, this seems like it will be usable once I get around to writing the help text generation.
39 lines
1.3 KiB
Zig
39 lines
1.3 KiB
Zig
const std = @import("std");
|
|
const builtin = std.builtin;
|
|
|
|
const noclip = @import("./noclip.zig");
|
|
|
|
pub fn stringHandler(comptime UserContext: type) HandlerType(.{ .UserContext = UserContext, .Output = []const u8 }) {
|
|
return struct {
|
|
pub fn handler(_: UserContext, buf: []const u8) ![]const u8 {
|
|
return buf;
|
|
}
|
|
}.handler;
|
|
}
|
|
|
|
pub fn intHandler(comptime UserContext: type, comptime IntType: type) HandlerType(.{ .UserContext = UserContext, .Output = IntType }) {
|
|
return struct {
|
|
pub fn handler(_: UserContext, buf: []const u8) std.fmt.ParseIntError!IntType {
|
|
return try std.fmt.parseInt(IntType, buf, 0);
|
|
}
|
|
}.handler;
|
|
}
|
|
|
|
pub fn HandlerType(comptime args: noclip.ParameterArgs) type {
|
|
return *const fn (args.UserContext, []const u8) anyerror!args.Output;
|
|
}
|
|
|
|
pub fn getDefaultHandler(comptime args: noclip.ParameterArgs) ?HandlerType(args) {
|
|
switch (@typeInfo(args.Output)) {
|
|
.Optional => |info| return getDefaultHandler(.{ .Output = info.child, .UserContext = args.user }),
|
|
.Int => return intHandler(args.UserContext, args.Output),
|
|
.Pointer => |info| {
|
|
if (info.size == .Slice and info.child == u8) {
|
|
return stringHandler(args.UserContext);
|
|
}
|
|
return null;
|
|
},
|
|
else => return null,
|
|
}
|
|
}
|