Skip to content

Commit

Permalink
Support enums as option values
Browse files Browse the repository at this point in the history
Closes #14
  • Loading branch information
sam701 committed Oct 14, 2023
1 parent 24651ab commit 5cad24c
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Inspired by [urfave/cli](https://github.com/urfave/cli) Go package.
* concatenated short options: `-a -b -c` equals `-abc`
* subcommands: `command1 -option1 subcommand2 -option2`
* multiple option values: `--opt val1 --opt val2 --opt val3`
* enums as option values: `--opt EnumValue1`
* options value can be read from environment variables with a configured prefix
* positional arguments can be mixed with options: `--opt1 val1 arg1 -v`
* stops option parsing after `--`: `command -- --abc` will consider `--abc` as a positional argument to `command`.
Expand Down
26 changes: 26 additions & 0 deletions src/tests.zig
Original file line number Diff line number Diff line change
Expand Up @@ -240,3 +240,29 @@ test "mix positional arguments and options" {
try std.testing.expectEqualStrings("--arg3", result.args[2]);
try std.testing.expectEqualStrings("-arg4", result.args[3]);
}

test "parse enums" {
const Aa = enum {
cc,
dd,
};
var aa: []Aa = undefined;
var aa_opt = command.Option{
.long_name = "aa",
.short_alias = 'a',
.help = "option aa",
.value_ref = mkRef(&aa),
};
var app = command.App{
.name = "abc",
.options = &.{&aa_opt},
.action = dummy_action,
};

_ = try run(&app, &.{ "abc", "--aa=cc", "--aa", "dd" });
try std.testing.expect(2 == aa.len);
try std.testing.expect(aa[0] == Aa.cc);
try std.testing.expect(aa[1] == Aa.dd);

alloc.free(aa);
}
21 changes: 21 additions & 0 deletions src/value_parser.zig
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub fn getValueData(comptime T: type) ValueData {
return stringData(T);
}
},
.Enum => enumData(ValueType, T),
else => @compileError("unsupported value type"),
};
}
Expand Down Expand Up @@ -79,3 +80,23 @@ fn stringData(comptime DestinationType: type) ValueData {
.type_name = "string",
};
}

fn enumData(comptime ValueType: type, comptime DestinationType: type) ValueData {
const edata = @typeInfo(ValueType).Enum;
return .{
.value_size = @sizeOf(DestinationType),
.value_parser = struct {
fn parser(dest: *anyopaque, value: []const u8) anyerror!void {
inline for (edata.fields) |field| {
if (std.mem.eql(u8, field.name, value)) {
const dt: *DestinationType = @ptrCast(@alignCast(dest));
dt.* = @field(ValueType, field.name);
return;
}
}
return error.InvalidEnumValue;
}
}.parser,
.type_name = "enum",
};
}

0 comments on commit 5cad24c

Please sign in to comment.