authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-06-04 20:50:36-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-06-04 20:50:36-07:00
logd2b7e48f6134a7babdbac72aadf63fba9f7abd58
tree0feafaee8b4d5acd4a616c2cfffa9c1d7ca60d7c
parent621844bde551ee1a9b8142d7d146d1fa804247a2

CLI: use stringToEnum for subcommand

Follow-up from ea3be3d4fe2c4f0aae29c2889c2079fb18133726

2 files changed, 20 insertions(+), 30 deletions(-)

lib/std/meta.zig+3-12
......@@ -15,7 +15,7 @@ test {
1515}
1616
1717/// Returns the variant of an enum type, `T`, which is named `str`, or `null` if no such variant exists.
18pub fn stringToEnum(comptime T: type, str: []const u8) ?T {
18pub fn stringToEnum(comptime T: type, tag_name: []const u8) ?T {
1919 // Using StaticStringMap here is more performant, but it will start to take too
2020 // long to compile if the enum is large enough, due to the current limits of comptime
2121 // performance when doing things like constructing lookup maps at comptime.
......@@ -23,19 +23,10 @@ pub fn stringToEnum(comptime T: type, str: []const u8) ?T {
2323 // - https://github.com/ziglang/zig/issues/4055
2424 // - https://github.com/ziglang/zig/issues/3863
2525 if (@typeInfo(T).@"enum".field_names.len <= 100) {
26 const kvs = comptime build_kvs: {
27 const EnumKV = struct { []const u8, T };
28 var kvs_array: [@typeInfo(T).@"enum".field_names.len]EnumKV = undefined;
29 for (@typeInfo(T).@"enum".field_names, 0..) |name, i| {
30 kvs_array[i] = .{ name, @field(T, name) };
31 }
32 break :build_kvs kvs_array[0..];
33 };
34 const map = std.StaticStringMap(T).initComptime(kvs);
35 return map.get(str);
26 return std.StaticStringMap(T).initEnum().get(tag_name);
3627 } else {
3728 inline for (@typeInfo(T).@"enum".field_names) |name| {
38 if (mem.eql(u8, str, name)) {
29 if (mem.eql(u8, tag_name, name)) {
3930 return @field(T, name);
4031 }
4132 }
src/main.zig+17-18
......@@ -20,6 +20,7 @@ const LibCInstallation = std.zig.LibCInstallation;
2020const AstGen = std.zig.AstGen;
2121const ZonGen = std.zig.ZonGen;
2222const Server = std.zig.Server;
23const stringToEnum = std.meta.stringToEnum;
2324
2425pub const tracy = @import("tracy.zig");
2526const Compilation = @import("Compilation.zig");
......@@ -229,8 +230,6 @@ pub fn main(init: std.process.Init.Minimal) anyerror!void {
229230 return mainArgs(gpa, arena, io, args, &environ_map);
230231}
231232
232const cmd_map = std.StaticStringMap(Cmd).initEnum();
233
234233const Cmd = enum {
235234 @"build-exe",
236235 @"build-lib",
......@@ -322,7 +321,7 @@ fn mainArgs(
322321
323322 const cmd = args[1];
324323 const cmd_args = args[2..];
325 switch (cmd_map.get(cmd) orelse {
324 switch (stringToEnum.get(Cmd, cmd) orelse {
326325 std.log.info("{s}", .{usage});
327326 fatal("unknown command: {s}", .{args[1]});
328327 }) {
......@@ -1220,7 +1219,7 @@ fn buildOutputType(
12201219 const next_arg = args_iter.next() orelse {
12211220 fatal("expected [auto|on|off] after --color", .{});
12221221 };
1223 color = std.meta.stringToEnum(Color, next_arg) orelse {
1222 color = stringToEnum(Color, next_arg) orelse {
12241223 fatal("expected [auto|on|off] after --color, found {q}", .{next_arg});
12251224 };
12261225 } else if (mem.cutPrefix(u8, arg, "-j")) |str| {
......@@ -1264,7 +1263,7 @@ fn buildOutputType(
12641263 } else if (mem.eql(u8, arg, "-install_name")) {
12651264 install_name = args_iter.nextOrFatal();
12661265 } else if (mem.cutPrefix(u8, arg, "--compress-debug-sections=")) |param| {
1267 linker_compress_debug_sections = std.meta.stringToEnum(std.zig.CompressDebugSections, param) orelse {
1266 linker_compress_debug_sections = stringToEnum(std.zig.CompressDebugSections, param) orelse {
12681267 fatal("expected --compress-debug-sections=[none|zlib|zstd], found: {s}", .{param});
12691268 };
12701269 } else if (mem.eql(u8, arg, "--compress-debug-sections")) {
......@@ -2516,7 +2515,7 @@ fn buildOutputType(
25162515 if (it.only_arg.len == 0) {
25172516 linker_compress_debug_sections = .zlib;
25182517 } else {
2519 linker_compress_debug_sections = std.meta.stringToEnum(std.zig.CompressDebugSections, it.only_arg) orelse {
2518 linker_compress_debug_sections = stringToEnum(std.zig.CompressDebugSections, it.only_arg) orelse {
25202519 fatal("expected [none|zlib|zstd] after --compress-debug-sections, found {q}", .{it.only_arg});
25212520 };
25222521 }
......@@ -2668,7 +2667,7 @@ fn buildOutputType(
26682667 linker_print_map = true;
26692668 } else if (mem.eql(u8, arg, "--sort-section")) {
26702669 const arg1 = linker_args_it.nextOrFatal();
2671 linker_sort_section = std.meta.stringToEnum(link.File.Lld.Elf.SortSection, arg1) orelse {
2670 linker_sort_section = stringToEnum(link.File.Lld.Elf.SortSection, arg1) orelse {
26722671 fatal("expected [name|alignment] after --sort-section, found {q}", .{arg1});
26732672 };
26742673 } else if (mem.eql(u8, arg, "--allow-shlib-undefined") or
......@@ -2724,7 +2723,7 @@ fn buildOutputType(
27242723 }
27252724 } else if (mem.eql(u8, arg, "--compress-debug-sections")) {
27262725 const arg1 = linker_args_it.nextOrFatal();
2727 linker_compress_debug_sections = std.meta.stringToEnum(std.zig.CompressDebugSections, arg1) orelse {
2726 linker_compress_debug_sections = stringToEnum(std.zig.CompressDebugSections, arg1) orelse {
27282727 fatal("expected [none|zlib|zstd] after --compress-debug-sections, found {q}", .{arg1});
27292728 };
27302729 } else if (mem.cutPrefix(u8, arg, "-z")) |z_rest| {
......@@ -2935,7 +2934,7 @@ fn buildOutputType(
29352934 mem.eql(u8, arg, "--hash-style"))
29362935 {
29372936 const next_arg = linker_args_it.nextOrFatal();
2938 hash_style = std.meta.stringToEnum(link.File.Lld.Elf.HashStyle, next_arg) orelse {
2937 hash_style = stringToEnum(link.File.Lld.Elf.HashStyle, next_arg) orelse {
29392938 fatal("expected [sysv|gnu|both] after --hash-style, found {q}", .{next_arg});
29402939 };
29412940 } else if (mem.eql(u8, arg, "-wrap")) {
......@@ -5091,7 +5090,7 @@ fn cmdBuild(
50915090 configure_argv.appendAssumeCapacity(arg); // Intentionally "--system" only; not the path.
50925091 continue;
50935092 } else if (mem.cutPrefix(u8, arg, "--color=")) |rest| {
5094 color = std.meta.stringToEnum(Color, rest) orelse
5093 color = stringToEnum(Color, rest) orelse
50955094 fatal("expected --color=[auto|on|off]; found {q}", .{arg});
50965095
50975096 try cached_passthru_configure.append(arena, @intCast(configure_argv.items.len));
......@@ -5103,7 +5102,7 @@ fn cmdBuild(
51035102 continue;
51045103 } else if (mem.cutPrefix(u8, arg, "--cache-poison=")) |rest| {
51055104 // Allow the configurer process to report parse failure.
5106 if (std.meta.stringToEnum(std.Build.Graph.CachePoison, rest)) |poison| {
5105 if (stringToEnum(std.Build.Graph.CachePoison, rest)) |poison| {
51075106 cache_poison = poison;
51085107 }
51095108 configure_argv.appendAssumeCapacity(arg);
......@@ -5155,7 +5154,7 @@ fn cmdBuild(
51555154 fetch_only = true;
51565155 } else if (mem.cutPrefix(u8, arg, "--fetch=")) |sub_arg| {
51575156 fetch_only = true;
5158 fetch_mode = std.meta.stringToEnum(Package.Fetch.JobQueue.Mode, sub_arg) orelse
5157 fetch_mode = stringToEnum(Package.Fetch.JobQueue.Mode, sub_arg) orelse
51595158 fatal("expected [needed|all] after \"--fetch=\", found: {s}", .{sub_arg});
51605159 } else if (mem.cutPrefix(u8, arg, "--fork=")) |sub_arg| {
51615160 try forks.append(arena, .init(sub_arg));
......@@ -6591,7 +6590,7 @@ pub const ClangArgIterator = struct {
65916590};
65926591
65936592fn parseCodeModel(arg: []const u8) std.lang.CodeModel {
6594 return std.meta.stringToEnum(std.lang.CodeModel, arg) orelse
6593 return stringToEnum(std.lang.CodeModel, arg) orelse
65956594 fatal("unsupported machine code model: {q}", .{arg});
65966595}
65976596
......@@ -6638,7 +6637,7 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map:
66386637 }
66396638 i += 1;
66406639 const next_arg = args[i];
6641 color = std.meta.stringToEnum(Color, next_arg) orelse {
6640 color = stringToEnum(Color, next_arg) orelse {
66426641 fatal("expected [auto|on|off] after --color, found {q}", .{next_arg});
66436642 };
66446643 } else {
......@@ -7020,7 +7019,7 @@ fn warnAboutForeignBinaries(
70207019}
70217020
70227021fn parseSubsystem(arg: []const u8) !std.zig.Subsystem {
7023 return std.meta.stringToEnum(std.zig.Subsystem, arg) orelse
7022 return stringToEnum(std.zig.Subsystem, arg) orelse
70247023 fatal("invalid: --subsystem: {q}. Options are:\n{s}", .{
70257024 arg,
70267025 \\ console
......@@ -7151,7 +7150,7 @@ fn accessFrameworkPath(
71517150}
71527151
71537152fn parseRcIncludes(arg: []const u8) std.zig.RcIncludes {
7154 return std.meta.stringToEnum(std.zig.RcIncludes, arg) orelse
7153 return stringToEnum(std.zig.RcIncludes, arg) orelse
71557154 fatal("unsupported rc includes type: {q}", .{arg});
71567155}
71577156
......@@ -7817,12 +7816,12 @@ fn findTemplates(gpa: Allocator, arena: Allocator, io: Io) Templates {
78177816}
78187817
78197818fn parseOptimizeMode(s: []const u8) std.lang.OptimizeMode {
7820 return std.meta.stringToEnum(std.lang.OptimizeMode, s) orelse
7819 return stringToEnum(std.lang.OptimizeMode, s) orelse
78217820 fatal("unrecognized optimization mode: {q}", .{s});
78227821}
78237822
78247823fn parseWasiExecModel(s: []const u8) std.lang.WasiExecModel {
7825 return std.meta.stringToEnum(std.lang.WasiExecModel, s) orelse
7824 return stringToEnum(std.lang.WasiExecModel, s) orelse
78267825 fatal("expected [command|reactor] for -mexec-mode=[value], found {q}", .{s});
78277826}
78287827