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 {...@@ -15,7 +15,7 @@ test {
15}15}
1616
17/// Returns the variant of an enum type, `T`, which is named `str`, or `null` if no such variant exists.17/// 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 {
19 // Using StaticStringMap here is more performant, but it will start to take too19 // Using StaticStringMap here is more performant, but it will start to take too
20 // long to compile if the enum is large enough, due to the current limits of comptime20 // long to compile if the enum is large enough, due to the current limits of comptime
21 // performance when doing things like constructing lookup maps at comptime.21 // performance when doing things like constructing lookup maps at comptime.
...@@ -23,19 +23,10 @@ pub fn stringToEnum(comptime T: type, str: []const u8) ?T {...@@ -23,19 +23,10 @@ pub fn stringToEnum(comptime T: type, str: []const u8) ?T {
23 // - https://github.com/ziglang/zig/issues/405523 // - https://github.com/ziglang/zig/issues/4055
24 // - https://github.com/ziglang/zig/issues/386324 // - https://github.com/ziglang/zig/issues/3863
25 if (@typeInfo(T).@"enum".field_names.len <= 100) {25 if (@typeInfo(T).@"enum".field_names.len <= 100) {
26 const kvs = comptime build_kvs: {26 return std.StaticStringMap(T).initEnum().get(tag_name);
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);
36 } else {27 } else {
37 inline for (@typeInfo(T).@"enum".field_names) |name| {28 inline for (@typeInfo(T).@"enum".field_names) |name| {
38 if (mem.eql(u8, str, name)) {29 if (mem.eql(u8, tag_name, name)) {
39 return @field(T, name);30 return @field(T, name);
40 }31 }
41 }32 }
src/main.zig+17-18
...@@ -20,6 +20,7 @@ const LibCInstallation = std.zig.LibCInstallation;...@@ -20,6 +20,7 @@ const LibCInstallation = std.zig.LibCInstallation;
20const AstGen = std.zig.AstGen;20const AstGen = std.zig.AstGen;
21const ZonGen = std.zig.ZonGen;21const ZonGen = std.zig.ZonGen;
22const Server = std.zig.Server;22const Server = std.zig.Server;
23const stringToEnum = std.meta.stringToEnum;
2324
24pub const tracy = @import("tracy.zig");25pub const tracy = @import("tracy.zig");
25const Compilation = @import("Compilation.zig");26const Compilation = @import("Compilation.zig");
...@@ -229,8 +230,6 @@ pub fn main(init: std.process.Init.Minimal) anyerror!void {...@@ -229,8 +230,6 @@ pub fn main(init: std.process.Init.Minimal) anyerror!void {
229 return mainArgs(gpa, arena, io, args, &environ_map);230 return mainArgs(gpa, arena, io, args, &environ_map);
230}231}
231232
232const cmd_map = std.StaticStringMap(Cmd).initEnum();
233
234const Cmd = enum {233const Cmd = enum {
235 @"build-exe",234 @"build-exe",
236 @"build-lib",235 @"build-lib",
...@@ -322,7 +321,7 @@ fn mainArgs(...@@ -322,7 +321,7 @@ fn mainArgs(
322321
323 const cmd = args[1];322 const cmd = args[1];
324 const cmd_args = args[2..];323 const cmd_args = args[2..];
325 switch (cmd_map.get(cmd) orelse {324 switch (stringToEnum.get(Cmd, cmd) orelse {
326 std.log.info("{s}", .{usage});325 std.log.info("{s}", .{usage});
327 fatal("unknown command: {s}", .{args[1]});326 fatal("unknown command: {s}", .{args[1]});
328 }) {327 }) {
...@@ -1220,7 +1219,7 @@ fn buildOutputType(...@@ -1220,7 +1219,7 @@ fn buildOutputType(
1220 const next_arg = args_iter.next() orelse {1219 const next_arg = args_iter.next() orelse {
1221 fatal("expected [auto|on|off] after --color", .{});1220 fatal("expected [auto|on|off] after --color", .{});
1222 };1221 };
1223 color = std.meta.stringToEnum(Color, next_arg) orelse {1222 color = stringToEnum(Color, next_arg) orelse {
1224 fatal("expected [auto|on|off] after --color, found {q}", .{next_arg});1223 fatal("expected [auto|on|off] after --color, found {q}", .{next_arg});
1225 };1224 };
1226 } else if (mem.cutPrefix(u8, arg, "-j")) |str| {1225 } else if (mem.cutPrefix(u8, arg, "-j")) |str| {
...@@ -1264,7 +1263,7 @@ fn buildOutputType(...@@ -1264,7 +1263,7 @@ fn buildOutputType(
1264 } else if (mem.eql(u8, arg, "-install_name")) {1263 } else if (mem.eql(u8, arg, "-install_name")) {
1265 install_name = args_iter.nextOrFatal();1264 install_name = args_iter.nextOrFatal();
1266 } else if (mem.cutPrefix(u8, arg, "--compress-debug-sections=")) |param| {1265 } 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 {
1268 fatal("expected --compress-debug-sections=[none|zlib|zstd], found: {s}", .{param});1267 fatal("expected --compress-debug-sections=[none|zlib|zstd], found: {s}", .{param});
1269 };1268 };
1270 } else if (mem.eql(u8, arg, "--compress-debug-sections")) {1269 } else if (mem.eql(u8, arg, "--compress-debug-sections")) {
...@@ -2516,7 +2515,7 @@ fn buildOutputType(...@@ -2516,7 +2515,7 @@ fn buildOutputType(
2516 if (it.only_arg.len == 0) {2515 if (it.only_arg.len == 0) {
2517 linker_compress_debug_sections = .zlib;2516 linker_compress_debug_sections = .zlib;
2518 } else {2517 } 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 {
2520 fatal("expected [none|zlib|zstd] after --compress-debug-sections, found {q}", .{it.only_arg});2519 fatal("expected [none|zlib|zstd] after --compress-debug-sections, found {q}", .{it.only_arg});
2521 };2520 };
2522 }2521 }
...@@ -2668,7 +2667,7 @@ fn buildOutputType(...@@ -2668,7 +2667,7 @@ fn buildOutputType(
2668 linker_print_map = true;2667 linker_print_map = true;
2669 } else if (mem.eql(u8, arg, "--sort-section")) {2668 } else if (mem.eql(u8, arg, "--sort-section")) {
2670 const arg1 = linker_args_it.nextOrFatal();2669 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 {
2672 fatal("expected [name|alignment] after --sort-section, found {q}", .{arg1});2671 fatal("expected [name|alignment] after --sort-section, found {q}", .{arg1});
2673 };2672 };
2674 } else if (mem.eql(u8, arg, "--allow-shlib-undefined") or2673 } else if (mem.eql(u8, arg, "--allow-shlib-undefined") or
...@@ -2724,7 +2723,7 @@ fn buildOutputType(...@@ -2724,7 +2723,7 @@ fn buildOutputType(
2724 }2723 }
2725 } else if (mem.eql(u8, arg, "--compress-debug-sections")) {2724 } else if (mem.eql(u8, arg, "--compress-debug-sections")) {
2726 const arg1 = linker_args_it.nextOrFatal();2725 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 {
2728 fatal("expected [none|zlib|zstd] after --compress-debug-sections, found {q}", .{arg1});2727 fatal("expected [none|zlib|zstd] after --compress-debug-sections, found {q}", .{arg1});
2729 };2728 };
2730 } else if (mem.cutPrefix(u8, arg, "-z")) |z_rest| {2729 } else if (mem.cutPrefix(u8, arg, "-z")) |z_rest| {
...@@ -2935,7 +2934,7 @@ fn buildOutputType(...@@ -2935,7 +2934,7 @@ fn buildOutputType(
2935 mem.eql(u8, arg, "--hash-style"))2934 mem.eql(u8, arg, "--hash-style"))
2936 {2935 {
2937 const next_arg = linker_args_it.nextOrFatal();2936 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 {
2939 fatal("expected [sysv|gnu|both] after --hash-style, found {q}", .{next_arg});2938 fatal("expected [sysv|gnu|both] after --hash-style, found {q}", .{next_arg});
2940 };2939 };
2941 } else if (mem.eql(u8, arg, "-wrap")) {2940 } else if (mem.eql(u8, arg, "-wrap")) {
...@@ -5091,7 +5090,7 @@ fn cmdBuild(...@@ -5091,7 +5090,7 @@ fn cmdBuild(
5091 configure_argv.appendAssumeCapacity(arg); // Intentionally "--system" only; not the path.5090 configure_argv.appendAssumeCapacity(arg); // Intentionally "--system" only; not the path.
5092 continue;5091 continue;
5093 } else if (mem.cutPrefix(u8, arg, "--color=")) |rest| {5092 } else if (mem.cutPrefix(u8, arg, "--color=")) |rest| {
5094 color = std.meta.stringToEnum(Color, rest) orelse5093 color = stringToEnum(Color, rest) orelse
5095 fatal("expected --color=[auto|on|off]; found {q}", .{arg});5094 fatal("expected --color=[auto|on|off]; found {q}", .{arg});
50965095
5097 try cached_passthru_configure.append(arena, @intCast(configure_argv.items.len));5096 try cached_passthru_configure.append(arena, @intCast(configure_argv.items.len));
...@@ -5103,7 +5102,7 @@ fn cmdBuild(...@@ -5103,7 +5102,7 @@ fn cmdBuild(
5103 continue;5102 continue;
5104 } else if (mem.cutPrefix(u8, arg, "--cache-poison=")) |rest| {5103 } else if (mem.cutPrefix(u8, arg, "--cache-poison=")) |rest| {
5105 // Allow the configurer process to report parse failure.5104 // 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| {
5107 cache_poison = poison;5106 cache_poison = poison;
5108 }5107 }
5109 configure_argv.appendAssumeCapacity(arg);5108 configure_argv.appendAssumeCapacity(arg);
...@@ -5155,7 +5154,7 @@ fn cmdBuild(...@@ -5155,7 +5154,7 @@ fn cmdBuild(
5155 fetch_only = true;5154 fetch_only = true;
5156 } else if (mem.cutPrefix(u8, arg, "--fetch=")) |sub_arg| {5155 } else if (mem.cutPrefix(u8, arg, "--fetch=")) |sub_arg| {
5157 fetch_only = true;5156 fetch_only = true;
5158 fetch_mode = std.meta.stringToEnum(Package.Fetch.JobQueue.Mode, sub_arg) orelse5157 fetch_mode = stringToEnum(Package.Fetch.JobQueue.Mode, sub_arg) orelse
5159 fatal("expected [needed|all] after \"--fetch=\", found: {s}", .{sub_arg});5158 fatal("expected [needed|all] after \"--fetch=\", found: {s}", .{sub_arg});
5160 } else if (mem.cutPrefix(u8, arg, "--fork=")) |sub_arg| {5159 } else if (mem.cutPrefix(u8, arg, "--fork=")) |sub_arg| {
5161 try forks.append(arena, .init(sub_arg));5160 try forks.append(arena, .init(sub_arg));
...@@ -6591,7 +6590,7 @@ pub const ClangArgIterator = struct {...@@ -6591,7 +6590,7 @@ pub const ClangArgIterator = struct {
6591};6590};
65926591
6593fn parseCodeModel(arg: []const u8) std.lang.CodeModel {6592fn parseCodeModel(arg: []const u8) std.lang.CodeModel {
6594 return std.meta.stringToEnum(std.lang.CodeModel, arg) orelse6593 return stringToEnum(std.lang.CodeModel, arg) orelse
6595 fatal("unsupported machine code model: {q}", .{arg});6594 fatal("unsupported machine code model: {q}", .{arg});
6596}6595}
65976596
...@@ -6638,7 +6637,7 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map:...@@ -6638,7 +6637,7 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map:
6638 }6637 }
6639 i += 1;6638 i += 1;
6640 const next_arg = args[i];6639 const next_arg = args[i];
6641 color = std.meta.stringToEnum(Color, next_arg) orelse {6640 color = stringToEnum(Color, next_arg) orelse {
6642 fatal("expected [auto|on|off] after --color, found {q}", .{next_arg});6641 fatal("expected [auto|on|off] after --color, found {q}", .{next_arg});
6643 };6642 };
6644 } else {6643 } else {
...@@ -7020,7 +7019,7 @@ fn warnAboutForeignBinaries(...@@ -7020,7 +7019,7 @@ fn warnAboutForeignBinaries(
7020}7019}
70217020
7022fn parseSubsystem(arg: []const u8) !std.zig.Subsystem {7021fn parseSubsystem(arg: []const u8) !std.zig.Subsystem {
7023 return std.meta.stringToEnum(std.zig.Subsystem, arg) orelse7022 return stringToEnum(std.zig.Subsystem, arg) orelse
7024 fatal("invalid: --subsystem: {q}. Options are:\n{s}", .{7023 fatal("invalid: --subsystem: {q}. Options are:\n{s}", .{
7025 arg,7024 arg,
7026 \\ console7025 \\ console
...@@ -7151,7 +7150,7 @@ fn accessFrameworkPath(...@@ -7151,7 +7150,7 @@ fn accessFrameworkPath(
7151}7150}
71527151
7153fn parseRcIncludes(arg: []const u8) std.zig.RcIncludes {7152fn parseRcIncludes(arg: []const u8) std.zig.RcIncludes {
7154 return std.meta.stringToEnum(std.zig.RcIncludes, arg) orelse7153 return stringToEnum(std.zig.RcIncludes, arg) orelse
7155 fatal("unsupported rc includes type: {q}", .{arg});7154 fatal("unsupported rc includes type: {q}", .{arg});
7156}7155}
71577156
...@@ -7817,12 +7816,12 @@ fn findTemplates(gpa: Allocator, arena: Allocator, io: Io) Templates {...@@ -7817,12 +7816,12 @@ fn findTemplates(gpa: Allocator, arena: Allocator, io: Io) Templates {
7817}7816}
78187817
7819fn parseOptimizeMode(s: []const u8) std.lang.OptimizeMode {7818fn parseOptimizeMode(s: []const u8) std.lang.OptimizeMode {
7820 return std.meta.stringToEnum(std.lang.OptimizeMode, s) orelse7819 return stringToEnum(std.lang.OptimizeMode, s) orelse
7821 fatal("unrecognized optimization mode: {q}", .{s});7820 fatal("unrecognized optimization mode: {q}", .{s});
7822}7821}
78237822
7824fn parseWasiExecModel(s: []const u8) std.lang.WasiExecModel {7823fn parseWasiExecModel(s: []const u8) std.lang.WasiExecModel {
7825 return std.meta.stringToEnum(std.lang.WasiExecModel, s) orelse7824 return stringToEnum(std.lang.WasiExecModel, s) orelse
7826 fatal("expected [command|reactor] for -mexec-mode=[value], found {q}", .{s});7825 fatal("expected [command|reactor] for -mexec-mode=[value], found {q}", .{s});
7827}7826}
78287827