From d2b7e48f6134a7babdbac72aadf63fba9f7abd58 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 4 Jun 2026 20:50:36 -0700 Subject: [PATCH] CLI: use stringToEnum for subcommand Follow-up from ea3be3d4fe2c4f0aae29c2889c2079fb18133726 --- lib/std/meta.zig | 15 +++------------ src/main.zig | 35 +++++++++++++++++------------------ 2 files changed, 20 insertions(+), 30 deletions(-) diff --git a/lib/std/meta.zig b/lib/std/meta.zig index 85f3171fa548a19a9b9f2d026f81f04e1762e464..2012f8cafe7c94647ff1bb992d91fc3dc22efc7f 100644 --- a/lib/std/meta.zig +++ b/lib/std/meta.zig @@ -15,7 +15,7 @@ test { } /// Returns the variant of an enum type, `T`, which is named `str`, or `null` if no such variant exists. -pub fn stringToEnum(comptime T: type, str: []const u8) ?T { +pub fn stringToEnum(comptime T: type, tag_name: []const u8) ?T { // Using StaticStringMap here is more performant, but it will start to take too // long to compile if the enum is large enough, due to the current limits of comptime // performance when doing things like constructing lookup maps at comptime. @@ -23,19 +23,10 @@ pub fn stringToEnum(comptime T: type, str: []const u8) ?T { // - https://github.com/ziglang/zig/issues/4055 // - https://github.com/ziglang/zig/issues/3863 if (@typeInfo(T).@"enum".field_names.len <= 100) { - const kvs = comptime build_kvs: { - const EnumKV = struct { []const u8, T }; - var kvs_array: [@typeInfo(T).@"enum".field_names.len]EnumKV = undefined; - for (@typeInfo(T).@"enum".field_names, 0..) |name, i| { - kvs_array[i] = .{ name, @field(T, name) }; - } - break :build_kvs kvs_array[0..]; - }; - const map = std.StaticStringMap(T).initComptime(kvs); - return map.get(str); + return std.StaticStringMap(T).initEnum().get(tag_name); } else { inline for (@typeInfo(T).@"enum".field_names) |name| { - if (mem.eql(u8, str, name)) { + if (mem.eql(u8, tag_name, name)) { return @field(T, name); } } diff --git a/src/main.zig b/src/main.zig index 30ac73098d9728201ce57db00b76c111f630c44c..7292ba6fa2d4117239a5a91da54c99143a731df2 100644 --- a/src/main.zig +++ b/src/main.zig @@ -20,6 +20,7 @@ const LibCInstallation = std.zig.LibCInstallation; const AstGen = std.zig.AstGen; const ZonGen = std.zig.ZonGen; const Server = std.zig.Server; +const stringToEnum = std.meta.stringToEnum; pub const tracy = @import("tracy.zig"); const Compilation = @import("Compilation.zig"); @@ -229,8 +230,6 @@ pub fn main(init: std.process.Init.Minimal) anyerror!void { return mainArgs(gpa, arena, io, args, &environ_map); } -const cmd_map = std.StaticStringMap(Cmd).initEnum(); - const Cmd = enum { @"build-exe", @"build-lib", @@ -322,7 +321,7 @@ fn mainArgs( const cmd = args[1]; const cmd_args = args[2..]; - switch (cmd_map.get(cmd) orelse { + switch (stringToEnum.get(Cmd, cmd) orelse { std.log.info("{s}", .{usage}); fatal("unknown command: {s}", .{args[1]}); }) { @@ -1220,7 +1219,7 @@ fn buildOutputType( const next_arg = args_iter.next() orelse { fatal("expected [auto|on|off] after --color", .{}); }; - color = std.meta.stringToEnum(Color, next_arg) orelse { + color = stringToEnum(Color, next_arg) orelse { fatal("expected [auto|on|off] after --color, found {q}", .{next_arg}); }; } else if (mem.cutPrefix(u8, arg, "-j")) |str| { @@ -1264,7 +1263,7 @@ fn buildOutputType( } else if (mem.eql(u8, arg, "-install_name")) { install_name = args_iter.nextOrFatal(); } else if (mem.cutPrefix(u8, arg, "--compress-debug-sections=")) |param| { - linker_compress_debug_sections = std.meta.stringToEnum(std.zig.CompressDebugSections, param) orelse { + linker_compress_debug_sections = stringToEnum(std.zig.CompressDebugSections, param) orelse { fatal("expected --compress-debug-sections=[none|zlib|zstd], found: {s}", .{param}); }; } else if (mem.eql(u8, arg, "--compress-debug-sections")) { @@ -2516,7 +2515,7 @@ fn buildOutputType( if (it.only_arg.len == 0) { linker_compress_debug_sections = .zlib; } else { - linker_compress_debug_sections = std.meta.stringToEnum(std.zig.CompressDebugSections, it.only_arg) orelse { + linker_compress_debug_sections = stringToEnum(std.zig.CompressDebugSections, it.only_arg) orelse { fatal("expected [none|zlib|zstd] after --compress-debug-sections, found {q}", .{it.only_arg}); }; } @@ -2668,7 +2667,7 @@ fn buildOutputType( linker_print_map = true; } else if (mem.eql(u8, arg, "--sort-section")) { const arg1 = linker_args_it.nextOrFatal(); - linker_sort_section = std.meta.stringToEnum(link.File.Lld.Elf.SortSection, arg1) orelse { + linker_sort_section = stringToEnum(link.File.Lld.Elf.SortSection, arg1) orelse { fatal("expected [name|alignment] after --sort-section, found {q}", .{arg1}); }; } else if (mem.eql(u8, arg, "--allow-shlib-undefined") or @@ -2724,7 +2723,7 @@ fn buildOutputType( } } else if (mem.eql(u8, arg, "--compress-debug-sections")) { const arg1 = linker_args_it.nextOrFatal(); - linker_compress_debug_sections = std.meta.stringToEnum(std.zig.CompressDebugSections, arg1) orelse { + linker_compress_debug_sections = stringToEnum(std.zig.CompressDebugSections, arg1) orelse { fatal("expected [none|zlib|zstd] after --compress-debug-sections, found {q}", .{arg1}); }; } else if (mem.cutPrefix(u8, arg, "-z")) |z_rest| { @@ -2935,7 +2934,7 @@ fn buildOutputType( mem.eql(u8, arg, "--hash-style")) { const next_arg = linker_args_it.nextOrFatal(); - hash_style = std.meta.stringToEnum(link.File.Lld.Elf.HashStyle, next_arg) orelse { + hash_style = stringToEnum(link.File.Lld.Elf.HashStyle, next_arg) orelse { fatal("expected [sysv|gnu|both] after --hash-style, found {q}", .{next_arg}); }; } else if (mem.eql(u8, arg, "-wrap")) { @@ -5091,7 +5090,7 @@ fn cmdBuild( configure_argv.appendAssumeCapacity(arg); // Intentionally "--system" only; not the path. continue; } else if (mem.cutPrefix(u8, arg, "--color=")) |rest| { - color = std.meta.stringToEnum(Color, rest) orelse + color = stringToEnum(Color, rest) orelse fatal("expected --color=[auto|on|off]; found {q}", .{arg}); try cached_passthru_configure.append(arena, @intCast(configure_argv.items.len)); @@ -5103,7 +5102,7 @@ fn cmdBuild( continue; } else if (mem.cutPrefix(u8, arg, "--cache-poison=")) |rest| { // Allow the configurer process to report parse failure. - if (std.meta.stringToEnum(std.Build.Graph.CachePoison, rest)) |poison| { + if (stringToEnum(std.Build.Graph.CachePoison, rest)) |poison| { cache_poison = poison; } configure_argv.appendAssumeCapacity(arg); @@ -5155,7 +5154,7 @@ fn cmdBuild( fetch_only = true; } else if (mem.cutPrefix(u8, arg, "--fetch=")) |sub_arg| { fetch_only = true; - fetch_mode = std.meta.stringToEnum(Package.Fetch.JobQueue.Mode, sub_arg) orelse + fetch_mode = stringToEnum(Package.Fetch.JobQueue.Mode, sub_arg) orelse fatal("expected [needed|all] after \"--fetch=\", found: {s}", .{sub_arg}); } else if (mem.cutPrefix(u8, arg, "--fork=")) |sub_arg| { try forks.append(arena, .init(sub_arg)); @@ -6591,7 +6590,7 @@ pub const ClangArgIterator = struct { }; fn parseCodeModel(arg: []const u8) std.lang.CodeModel { - return std.meta.stringToEnum(std.lang.CodeModel, arg) orelse + return stringToEnum(std.lang.CodeModel, arg) orelse fatal("unsupported machine code model: {q}", .{arg}); } @@ -6638,7 +6637,7 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map: } i += 1; const next_arg = args[i]; - color = std.meta.stringToEnum(Color, next_arg) orelse { + color = stringToEnum(Color, next_arg) orelse { fatal("expected [auto|on|off] after --color, found {q}", .{next_arg}); }; } else { @@ -7020,7 +7019,7 @@ fn warnAboutForeignBinaries( } fn parseSubsystem(arg: []const u8) !std.zig.Subsystem { - return std.meta.stringToEnum(std.zig.Subsystem, arg) orelse + return stringToEnum(std.zig.Subsystem, arg) orelse fatal("invalid: --subsystem: {q}. Options are:\n{s}", .{ arg, \\ console @@ -7151,7 +7150,7 @@ fn accessFrameworkPath( } fn parseRcIncludes(arg: []const u8) std.zig.RcIncludes { - return std.meta.stringToEnum(std.zig.RcIncludes, arg) orelse + return stringToEnum(std.zig.RcIncludes, arg) orelse fatal("unsupported rc includes type: {q}", .{arg}); } @@ -7817,12 +7816,12 @@ fn findTemplates(gpa: Allocator, arena: Allocator, io: Io) Templates { } fn parseOptimizeMode(s: []const u8) std.lang.OptimizeMode { - return std.meta.stringToEnum(std.lang.OptimizeMode, s) orelse + return stringToEnum(std.lang.OptimizeMode, s) orelse fatal("unrecognized optimization mode: {q}", .{s}); } fn parseWasiExecModel(s: []const u8) std.lang.WasiExecModel { - return std.meta.stringToEnum(std.lang.WasiExecModel, s) orelse + return stringToEnum(std.lang.WasiExecModel, s) orelse fatal("expected [command|reactor] for -mexec-mode=[value], found {q}", .{s}); } -- 2.54.0