122 lines
4.0 KiB
Zig
122 lines
4.0 KiB
Zig
|
const std = @import("std");
|
||
|
|
||
|
const ParameterGenerics = @import("./doodle.zig").ParameterGenerics;
|
||
|
const CommandError = @import("./doodle.zig").Errors;
|
||
|
|
||
|
pub const ConversionError = error{
|
||
|
BadValue,
|
||
|
};
|
||
|
|
||
|
pub fn ConverterSignature(comptime gen: ParameterGenerics) type {
|
||
|
return if (gen.no_context())
|
||
|
*const fn ([]const u8) ConversionError!gen.ResultType()
|
||
|
else
|
||
|
*const fn (gen.ContextType, []const u8) ConversionError!gen.ResultType();
|
||
|
}
|
||
|
|
||
|
pub fn default_converter(comptime gen: ParameterGenerics) ?ConverterSignature(gen) {
|
||
|
return switch (@typeInfo(gen.ResultType())) {
|
||
|
.Bool => flag_converter(gen),
|
||
|
.Int => int_converter(gen),
|
||
|
.Pointer => |info| if (info.size == .Slice and info.child == u8)
|
||
|
string_converter(gen)
|
||
|
else
|
||
|
null,
|
||
|
.Enum => choice_converter(gen),
|
||
|
else => null,
|
||
|
};
|
||
|
}
|
||
|
|
||
|
fn flag_converter(comptime gen: ParameterGenerics) ConverterSignature(gen) {
|
||
|
return if (gen.no_context())
|
||
|
struct {
|
||
|
pub fn handler(input: []const u8) ConversionError!bool {
|
||
|
// treat an empty string as falsy
|
||
|
if (input.len == 0) return false;
|
||
|
|
||
|
if (input.len <= 5) {
|
||
|
var lowerBuf: [5]u8 = undefined;
|
||
|
const comp = std.ascii.lowerString(&lowerBuf, input);
|
||
|
|
||
|
inline for ([_][]const u8{ "false", "no", "0" }) |candidate| {
|
||
|
if (std.mem.eql(u8, comp, candidate)) return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
}.handler
|
||
|
else
|
||
|
struct {
|
||
|
pub fn handler(_: gen.ContextType, input: []const u8) ConversionError!bool {
|
||
|
// treat an empty string as falsy
|
||
|
if (input.len == 0) return false;
|
||
|
|
||
|
if (input.len <= 5) {
|
||
|
var lowerBuf: [5]u8 = undefined;
|
||
|
const comp = std.ascii.lowerString(&lowerBuf, input);
|
||
|
|
||
|
inline for ([_][]const u8{ "false", "no", "0" }) |candidate| {
|
||
|
if (std.mem.eql(u8, comp, candidate)) return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
}.handler;
|
||
|
}
|
||
|
|
||
|
fn string_converter(comptime gen: ParameterGenerics) ConverterSignature(gen) {
|
||
|
return if (gen.no_context())
|
||
|
struct {
|
||
|
pub fn handler(value: []const u8) ConversionError![]const u8 {
|
||
|
return value;
|
||
|
}
|
||
|
}.handler
|
||
|
else
|
||
|
struct {
|
||
|
pub fn handler(_: gen.ContextType, value: []const u8) ConversionError![]const u8 {
|
||
|
return value;
|
||
|
}
|
||
|
}.handler;
|
||
|
}
|
||
|
|
||
|
fn int_converter(comptime gen: ParameterGenerics) ConverterSignature(gen) {
|
||
|
const IntType = gen.ResultType();
|
||
|
|
||
|
std.debug.assert(switch (@typeInfo(IntType)) {
|
||
|
.Int => true,
|
||
|
else => false,
|
||
|
});
|
||
|
|
||
|
return if (gen.no_context())
|
||
|
struct {
|
||
|
pub fn handler(value: []const u8) ConversionError!IntType {
|
||
|
return std.fmt.parseInt(IntType, value, 0) catch return ConversionError.BadValue;
|
||
|
}
|
||
|
}.handler
|
||
|
else
|
||
|
struct {
|
||
|
pub fn handler(_: gen.ContextType, value: []const u8) ConversionError!IntType {
|
||
|
return std.fmt.parseInt(IntType, value, 0) catch return ConversionError.BadValue;
|
||
|
}
|
||
|
}.handler;
|
||
|
}
|
||
|
|
||
|
fn choice_converter(comptime gen: ParameterGenerics) ConverterSignature(gen) {
|
||
|
const EnumType = gen.ResultType();
|
||
|
|
||
|
return if (gen.no_context())
|
||
|
struct {
|
||
|
pub fn handler(value: []const u8) ConversionError!EnumType {
|
||
|
return std.meta.stringToEnum(gen.ResultType(), value) orelse ConversionError.BadValue;
|
||
|
}
|
||
|
}.handler
|
||
|
else
|
||
|
struct {
|
||
|
pub fn handler(_: gen.ContextType, value: []const u8) ConversionError!EnumType {
|
||
|
return std.meta.stringToEnum(gen.ResultType(), value) orelse ConversionError.BadValue;
|
||
|
}
|
||
|
}.handler;
|
||
|
}
|