authorgravatar for r00ster91@proton.meWooster <r00ster91@proton.me> 2025-05-11 17:38:16+09:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2025-05-13 07:28:41+02:00
loga365971a337116dd23df2b1bc86468d54885b4b2
tree070dfe739796151d4d1256a3cedd83989609be42
parenta3693aae3a9417c4298788af570762945b21ccba

std.meta.intToEnum -> std.enums.fromInt

Also use an optional as the return type instead of an error code.

9 files changed, 64 insertions(+), 67 deletions(-)

lib/compiler/resinator/cli.zig+2-2
......@@ -354,9 +354,9 @@ pub const Options = struct {
354354
355355 const language_id = self.default_language_id orelse res.Language.default;
356356 const language_name = language_name: {
357 if (std.meta.intToEnum(lang.LanguageId, language_id)) |lang_enum_val| {
357 if (std.enums.fromInt(lang.LanguageId, language_id)) |lang_enum_val| {
358358 break :language_name @tagName(lang_enum_val);
359 } else |_| {}
359 }
360360 if (language_id == lang.LOCALE_CUSTOM_UNSPECIFIED) {
361361 break :language_name "LOCALE_CUSTOM_UNSPECIFIED";
362362 }
lib/compiler/resinator/res.zig+2-2
......@@ -173,9 +173,9 @@ pub const Language = packed struct(u16) {
173173 _ = options;
174174 const language_id = language.asInt();
175175 const language_name = language_name: {
176 if (std.meta.intToEnum(lang.LanguageId, language_id)) |lang_enum_val| {
176 if (std.enums.fromInt(lang.LanguageId, language_id)) |lang_enum_val| {
177177 break :language_name @tagName(lang_enum_val);
178 } else |_| {}
178 }
179179 if (language_id == lang.LOCALE_CUSTOM_UNSPECIFIED) {
180180 break :language_name "LOCALE_CUSTOM_UNSPECIFIED";
181181 }
lib/std/Build/Step/CheckObject.zig+5-5
......@@ -2445,7 +2445,7 @@ const WasmDumper = struct {
24452445 switch (check.kind) {
24462446 .headers => {
24472447 while (reader.readByte()) |current_byte| {
2448 const section = std.meta.intToEnum(std.wasm.Section, current_byte) catch {
2448 const section = std.enums.fromInt(std.wasm.Section, current_byte) orelse {
24492449 return step.fail("Found invalid section id '{d}'", .{current_byte});
24502450 };
24512451
......@@ -2551,7 +2551,7 @@ const WasmDumper = struct {
25512551 const name = data[fbs.pos..][0..name_len];
25522552 fbs.pos += name_len;
25532553
2554 const kind = std.meta.intToEnum(std.wasm.ExternalKind, try reader.readByte()) catch {
2554 const kind = std.enums.fromInt(std.wasm.ExternalKind, try reader.readByte()) orelse {
25552555 return step.fail("invalid import kind", .{});
25562556 };
25572557
......@@ -2613,7 +2613,7 @@ const WasmDumper = struct {
26132613 const name = data[fbs.pos..][0..name_len];
26142614 fbs.pos += name_len;
26152615 const kind_byte = try std.leb.readUleb128(u8, reader);
2616 const kind = std.meta.intToEnum(std.wasm.ExternalKind, kind_byte) catch {
2616 const kind = std.enums.fromInt(std.wasm.ExternalKind, kind_byte) orelse {
26172617 return step.fail("invalid export kind value '{d}'", .{kind_byte});
26182618 };
26192619 const index = try std.leb.readUleb128(u32, reader);
......@@ -2664,7 +2664,7 @@ const WasmDumper = struct {
26642664
26652665 fn parseDumpType(step: *Step, comptime E: type, reader: anytype, writer: anytype) !E {
26662666 const byte = try reader.readByte();
2667 const tag = std.meta.intToEnum(E, byte) catch {
2667 const tag = std.enums.fromInt(E, byte) orelse {
26682668 return step.fail("invalid wasm type value '{d}'", .{byte});
26692669 };
26702670 try writer.print("type {s}\n", .{@tagName(tag)});
......@@ -2683,7 +2683,7 @@ const WasmDumper = struct {
26832683
26842684 fn parseDumpInit(step: *Step, reader: anytype, writer: anytype) !void {
26852685 const byte = try reader.readByte();
2686 const opcode = std.meta.intToEnum(std.wasm.Opcode, byte) catch {
2686 const opcode = std.enums.fromInt(std.wasm.Opcode, byte) orelse {
26872687 return step.fail("invalid wasm opcode '{d}'", .{byte});
26882688 };
26892689 switch (opcode) {
lib/std/enums.zig+43
......@@ -8,6 +8,25 @@ const EnumField = std.builtin.Type.EnumField;
88/// Increment this value when adding APIs that add single backwards branches.
99const eval_branch_quota_cushion = 10;
1010
11pub fn fromInt(comptime E: type, integer: anytype) ?E {
12 const enum_info = @typeInfo(E).@"enum";
13 if (!enum_info.is_exhaustive) {
14 if (std.math.cast(enum_info.tag_type, integer)) |tag| {
15 return @enumFromInt(tag);
16 }
17 return null;
18 }
19 // We don't directly iterate over the fields of E, as that
20 // would require an inline loop. Instead, we create an array of
21 // values that is comptime-know, but can be iterated at runtime
22 // without requiring an inline loop.
23 // This generates better machine code.
24 for (values(E)) |value| {
25 if (@intFromEnum(value) == integer) return @enumFromInt(integer);
26 }
27 return null;
28}
29
1130/// Returns a struct with a field matching each unique named enum element.
1231/// If the enum is extern and has multiple names for the same value, only
1332/// the first name is used. Each field is of type Data and has the provided
......@@ -239,6 +258,30 @@ test nameCast {
239258 try testing.expectEqual(B.b, nameCast(B, "b"));
240259}
241260
261test fromInt {
262 const E1 = enum {
263 A,
264 };
265 const E2 = enum {
266 A,
267 B,
268 };
269 const E3 = enum(i8) { A, _ };
270
271 var zero: u8 = 0;
272 var one: u16 = 1;
273 _ = &zero;
274 _ = &one;
275 try testing.expect(fromInt(E1, zero).? == E1.A);
276 try testing.expect(fromInt(E2, one).? == E2.B);
277 try testing.expect(fromInt(E3, zero).? == E3.A);
278 try testing.expect(fromInt(E3, 127).? == @as(E3, @enumFromInt(127)));
279 try testing.expect(fromInt(E3, -128).? == @as(E3, @enumFromInt(-128)));
280 try testing.expectEqual(null, fromInt(E1, one));
281 try testing.expectEqual(null, fromInt(E3, 128));
282 try testing.expectEqual(null, fromInt(E3, -129));
283}
284
242285/// A set of enum elements, backed by a bitfield. If the enum
243286/// is exhaustive but not dense, a mapping will be constructed from enum values
244287/// to dense indices. This type does no dynamic allocation and
lib/std/json/static.zig+2-2
......@@ -595,7 +595,7 @@ pub fn innerParseFromValue(
595595
596596 switch (source) {
597597 .float => return error.InvalidEnumTag,
598 .integer => |i| return std.meta.intToEnum(T, i),
598 .integer => |i| return std.enums.fromInt(T, i) orelse return error.InvalidEnumTag,
599599 .number_string, .string => |s| return sliceToEnum(T, s),
600600 else => return error.UnexpectedToken,
601601 }
......@@ -780,7 +780,7 @@ fn sliceToEnum(comptime T: type, slice: []const u8) !T {
780780 // Check for a numeric value.
781781 if (!isNumberFormattedLikeAnInteger(slice)) return error.InvalidEnumTag;
782782 const n = std.fmt.parseInt(@typeInfo(T).@"enum".tag_type, slice, 10) catch return error.InvalidEnumTag;
783 return std.meta.intToEnum(T, n);
783 return std.enums.fromInt(T, n) orelse return error.InvalidEnumTag;
784784}
785785
786786fn fillDefaultStructValues(comptime T: type, r: *T, fields_seen: *[@typeInfo(T).@"struct".fields.len]bool) !void {
lib/std/meta.zig+3-49
......@@ -857,58 +857,12 @@ test eql {
857857 try testing.expect(!eql(CU{ .a = {} }, .b));
858858}
859859
860test intToEnum {
861 const E1 = enum {
862 A,
863 };
864 const E2 = enum {
865 A,
866 B,
867 };
868 const E3 = enum(i8) { A, _ };
869
870 var zero: u8 = 0;
871 var one: u16 = 1;
872 _ = &zero;
873 _ = &one;
874 try testing.expect(intToEnum(E1, zero) catch unreachable == E1.A);
875 try testing.expect(intToEnum(E2, one) catch unreachable == E2.B);
876 try testing.expect(intToEnum(E3, zero) catch unreachable == E3.A);
877 try testing.expect(intToEnum(E3, 127) catch unreachable == @as(E3, @enumFromInt(127)));
878 try testing.expect(intToEnum(E3, -128) catch unreachable == @as(E3, @enumFromInt(-128)));
879 try testing.expectError(error.InvalidEnumTag, intToEnum(E1, one));
880 try testing.expectError(error.InvalidEnumTag, intToEnum(E3, 128));
881 try testing.expectError(error.InvalidEnumTag, intToEnum(E3, -129));
882}
883
860/// Deprecated: use `std.enums.fromInt` instead and handle null.
884861pub const IntToEnumError = error{InvalidEnumTag};
885862
863/// Deprecated: use `std.enums.fromInt` instead and handle null instead of an error.
886864pub fn intToEnum(comptime EnumTag: type, tag_int: anytype) IntToEnumError!EnumTag {
887 const enum_info = @typeInfo(EnumTag).@"enum";
888
889 if (!enum_info.is_exhaustive) {
890 if (std.math.cast(enum_info.tag_type, tag_int)) |tag| {
891 return @as(EnumTag, @enumFromInt(tag));
892 }
893 return error.InvalidEnumTag;
894 }
895
896 // We don't directly iterate over the fields of EnumTag, as that
897 // would require an inline loop. Instead, we create an array of
898 // values that is comptime-know, but can be iterated at runtime
899 // without requiring an inline loop. This generates better
900 // machine code.
901 const values = comptime blk: {
902 var result: [enum_info.fields.len]enum_info.tag_type = undefined;
903 for (&result, enum_info.fields) |*dst, src| {
904 dst.* = src.value;
905 }
906 break :blk result;
907 };
908 for (values) |v| {
909 if (v == tag_int) return @enumFromInt(tag_int);
910 }
911 return error.InvalidEnumTag;
865 return std.enums.fromInt(EnumTag, tag_int) orelse return error.InvalidEnumTag;
912866}
913867
914868/// Given a type and a name, return the field index according to source order.
src/Package/Fetch/git.zig+2-2
......@@ -313,7 +313,7 @@ pub const Repository = struct {
313313 unused: u3,
314314 type: u4,
315315 } = @bitCast(std.fmt.parseUnsigned(u16, iterator.data[iterator.pos..mode_end], 8) catch return error.InvalidTree);
316 const @"type" = std.meta.intToEnum(Entry.Type, mode.type) catch return error.InvalidTree;
316 const @"type" = std.enums.fromInt(Entry.Type, mode.type) orelse return error.InvalidTree;
317317 const executable = switch (mode.permission) {
318318 0 => if (@"type" == .file) return error.InvalidTree else false,
319319 0o644 => if (@"type" != .file) return error.InvalidTree else false,
......@@ -1144,7 +1144,7 @@ const EntryHeader = union(Type) {
11441144 const rest_len = if (initial.has_next) try readSizeVarInt(reader) else 0;
11451145 var uncompressed_length: u64 = initial.len;
11461146 uncompressed_length |= std.math.shlExact(u64, rest_len, 4) catch return error.InvalidFormat;
1147 const @"type" = std.meta.intToEnum(EntryHeader.Type, initial.type) catch return error.InvalidFormat;
1147 const @"type" = std.enums.fromInt(EntryHeader.Type, initial.type) orelse return error.InvalidFormat;
11481148 return switch (@"type") {
11491149 inline .commit, .tree, .blob, .tag => |tag| @unionInit(EntryHeader, @tagName(tag), .{
11501150 .uncompressed_length = uncompressed_length,
src/Value.zig+1-1
......@@ -3814,7 +3814,7 @@ pub fn interpret(val: Value, comptime T: type, pt: Zcu.PerThread) error{ OutOfMe
38143814 .@"enum" => switch (interpret_mode) {
38153815 .direct => {
38163816 const int = val.getUnsignedInt(zcu) orelse return error.TypeMismatch;
3817 return std.meta.intToEnum(T, int) catch error.TypeMismatch;
3817 return std.enums.fromInt(T, int) orelse error.TypeMismatch;
38183818 },
38193819 .by_name => {
38203820 const field_index = ty.enumTagFieldIndex(val, zcu) orelse return error.TypeMismatch;
test/behavior/enum.zig+4-4
......@@ -19,16 +19,16 @@ test "enum to int" {
1919 try shouldEqual(Number.Four, 4);
2020}
2121
22fn testIntToEnumEval(x: i32) !void {
23 try expect(@as(IntToEnumNumber, @enumFromInt(x)) == IntToEnumNumber.Three);
22fn testEnumFromIntEval(x: i32) !void {
23 try expect(@as(EnumFromIntNumber, @enumFromInt(x)) == EnumFromIntNumber.Three);
2424}
25const IntToEnumNumber = enum { Zero, One, Two, Three, Four };
25const EnumFromIntNumber = enum { Zero, One, Two, Three, Four };
2626
2727test "int to enum" {
2828 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2929 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3030
31 try testIntToEnumEval(3);
31 try testEnumFromIntEval(3);
3232}
3333
3434const ValueCount1 = enum {