Skip to content

Commit a365971

Browse files
wooster0alexrp
authored andcommitted
std.meta.intToEnum -> std.enums.fromInt
Also use an optional as the return type instead of an error code.
1 parent a3693aa commit a365971

File tree

9 files changed

+64
-67
lines changed

9 files changed

+64
-67
lines changed

lib/compiler/resinator/cli.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,25 @@ const EnumField = std.builtin.Type.EnumField;
88
/// Increment this value when adding APIs that add single backwards branches.
99
const eval_branch_quota_cushion = 10;
1010

11+
pub 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

261+
test 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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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

786786
fn fillDefaultStructValues(comptime T: type, r: *T, fields_seen: *[@typeInfo(T).@"struct".fields.len]bool) !void {

lib/std/meta.zig

Lines changed: 3 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -857,58 +857,12 @@ test eql {
857857
try testing.expect(!eql(CU{ .a = {} }, .b));
858858
}
859859

860-
test 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.
884861
pub const IntToEnumError = error{InvalidEnumTag};
885862

863+
/// Deprecated: use `std.enums.fromInt` instead and handle null instead of an error.
886864
pub 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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,16 @@ test "enum to int" {
1919
try shouldEqual(Number.Four, 4);
2020
}
2121

22-
fn testIntToEnumEval(x: i32) !void {
23-
try expect(@as(IntToEnumNumber, @enumFromInt(x)) == IntToEnumNumber.Three);
22+
fn testEnumFromIntEval(x: i32) !void {
23+
try expect(@as(EnumFromIntNumber, @enumFromInt(x)) == EnumFromIntNumber.Three);
2424
}
25-
const IntToEnumNumber = enum { Zero, One, Two, Three, Four };
25+
const EnumFromIntNumber = enum { Zero, One, Two, Three, Four };
2626

2727
test "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

3434
const ValueCount1 = enum {

0 commit comments

Comments
 (0)