Skip to content

Commit

Permalink
Fixed Enum Handling f/ Values
Browse files Browse the repository at this point in the history
- Fixed the `ofType()` function of `Value.Custom` to properly handle Enums by assigning a parsing function.
- Created the new `asEnumTag()` Parsing Function Builder for Values.
- Created the `log_enum.zig` example.
  • Loading branch information
00JCIV00 committed May 21, 2024
1 parent b49e22d commit a3ba567
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 6 deletions.
20 changes: 16 additions & 4 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ pub fn build(b: *std.Build) void {
cova_demo,
.{
.kinds = &.{ .all },
.version = "0.10.0",
.ver_date = "16 MAY 2024",
.version = "0.10.1",
.ver_date = "21 MAY 2024",
.author = "00JCIV00",
.copyright = "MIT License",
.help_docs_config = .{
Expand Down Expand Up @@ -109,8 +109,8 @@ pub fn build(b: *std.Build) void {
basic_app,
.{
.kinds = &.{ .all },
.version = "0.10.0",
.ver_date = "06 APR 2024",
.version = "0.10.1",
.ver_date = "21 MAY 2024",
.author = "00JCIV00",
.copyright = "MIT License",
.help_docs_config = .{
Expand All @@ -127,6 +127,18 @@ pub fn build(b: *std.Build) void {
);
const basic_app_gen_step = b.step("basic-app-gen", "Generate Meta Docs for the 'basic-app'");
basic_app_gen_step.dependOn(&basic_app_gen.step);

// - Log Enum Exe
const log_enum = b.addExecutable(.{
.name = bin_name orelse "log-enum",
.root_source_file = b.path("examples/log_enum.zig"),
.target = target,
.optimize = optimize,
});
log_enum.root_module.addImport("cova", cova_mod);
const build_log_enum = b.addInstallArtifact(log_enum, .{});
const build_log_enum_step = b.step("log-enum", "Build the 'log-enum' example (default: Debug)");
build_log_enum_step.dependOn(&build_log_enum.step);
}


Expand Down
51 changes: 51 additions & 0 deletions examples/log_enum.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
const std = @import("std");
const log = std.log;
const cova = @import("cova");

// We need to add any Enums we're using to our Value Config.
const CommandT = cova.Command.Custom(.{
.val_config = .{
.custom_types = &.{ log.Level },
},
});
const setup_cmd = CommandT{
.name = "log_enum",
.description = "A small demo of using the Log Level Enum as an Option.",
.opts = &.{
.{
.name = "log_level",
.description = "An Option using the `log.Level` Enum.",
.long_name = "log-level",
.mandatory = true,
.val = CommandT.ValueT.ofType(log.Level, .{
.name = "log_level_val",
.description = " This Value will handle then Enum."
})
}
},
};

pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
const alloc = gpa.allocator();
defer if (gpa.deinit() != .ok and gpa.detectLeaks()) log.err("Memory leak detected!", .{});
const stdout = std.io.getStdOut().writer();

var main_cmd = try setup_cmd.init(alloc, .{});
defer main_cmd.deinit();
var args_iter = try cova.ArgIteratorGeneric.init(alloc);
defer args_iter.deinit();

cova.parseArgs(&args_iter, CommandT, main_cmd, stdout, .{}) catch |err| switch (err) {
error.UsageHelpCalled => {},
else => return err,
};

const main_opts = try main_cmd.getOpts(.{});
const log_lvl_opt = main_opts.get("log_level").?;
const log_lvl = log_lvl_opt.val.getAs(log.Level) catch {
log.err("The provided Log Level was invalid.", .{});
return;
};
log.info("Provided Log Level: {s}", .{ @tagName(log_lvl) });
}
23 changes: 21 additions & 2 deletions src/Value.zig
Original file line number Diff line number Diff line change
Expand Up @@ -776,7 +776,14 @@ pub fn Custom(comptime config: Config) type {
if (T == []const u8) "string"
//else if (@typeInfo(T) == .Enum) @typeName(@typeInfo(T).Enum.tag_type)
else @typeName(T);
return @This(){ .generic = @unionInit(GenericT, active_tag, typed_val) };
const out_val =
if (@typeInfo(T) == .Enum and typed_val.parse_fn == null) outVal: {
var o_val = typed_val;
o_val.parse_fn = ParsingFns.Builder.asEnumTag(T);
break :outVal o_val;
}
else typed_val;
return @This(){ .generic = @unionInit(GenericT, active_tag, out_val) };
}

/// Config for creating Values from Componenet Types (Function Parameters, Struct Fields, and Union Fields) using `from()`.
Expand Down Expand Up @@ -968,7 +975,7 @@ pub const ParsingFns = struct {
}.toBase;
}

/// Parse the given argument token (`arg`) to an Enum Tag of the provided `EnumT`.
/// Parse the given argument token (`arg`) to an Int based on the Enum Tag Type of the provided `EnumT`.
pub fn asEnumType(comptime EnumT: type) enumFnType: {
const enum_info = @typeInfo(EnumT);
if (enum_info != .Enum) @compileError("The type of `EnumT` must be Enum!");
Expand All @@ -984,6 +991,18 @@ pub const ParsingFns = struct {
}.enumInt;
}

/// Parse the given argument token (`arg`) to an Enum Tag of the provided `EnumT`.
pub fn asEnumTag(comptime EnumT: type) enumFnType: {
const enum_info = @typeInfo(EnumT);
if (enum_info != .Enum) @compileError("The type of `EnumT` must be Enum!");
break :enumFnType fn([]const u8, mem.Allocator) anyerror!EnumT;
} {
return struct {
fn enumTag(arg: []const u8, _: mem.Allocator) !EnumT {
return meta.stringToEnum(EnumT, mem.trim(u8, arg, &.{ 0, ' ', '\t' })) orelse error.EnumTagDoesNotExist;
}
}.enumTag;
}
};

/// Trim all Whitespace from the beginning and end of the provided argument token (`arg`).
Expand Down

0 comments on commit a3ba567

Please sign in to comment.