Commit a365971a33
Changed files (9)
lib
std
test
behavior
lib/compiler/resinator/cli.zig
@@ -354,9 +354,9 @@ pub const Options = struct {
const language_id = self.default_language_id orelse res.Language.default;
const language_name = language_name: {
- if (std.meta.intToEnum(lang.LanguageId, language_id)) |lang_enum_val| {
+ if (std.enums.fromInt(lang.LanguageId, language_id)) |lang_enum_val| {
break :language_name @tagName(lang_enum_val);
- } else |_| {}
+ }
if (language_id == lang.LOCALE_CUSTOM_UNSPECIFIED) {
break :language_name "LOCALE_CUSTOM_UNSPECIFIED";
}
lib/compiler/resinator/res.zig
@@ -173,9 +173,9 @@ pub const Language = packed struct(u16) {
_ = options;
const language_id = language.asInt();
const language_name = language_name: {
- if (std.meta.intToEnum(lang.LanguageId, language_id)) |lang_enum_val| {
+ if (std.enums.fromInt(lang.LanguageId, language_id)) |lang_enum_val| {
break :language_name @tagName(lang_enum_val);
- } else |_| {}
+ }
if (language_id == lang.LOCALE_CUSTOM_UNSPECIFIED) {
break :language_name "LOCALE_CUSTOM_UNSPECIFIED";
}
lib/std/Build/Step/CheckObject.zig
@@ -2445,7 +2445,7 @@ const WasmDumper = struct {
switch (check.kind) {
.headers => {
while (reader.readByte()) |current_byte| {
- const section = std.meta.intToEnum(std.wasm.Section, current_byte) catch {
+ const section = std.enums.fromInt(std.wasm.Section, current_byte) orelse {
return step.fail("Found invalid section id '{d}'", .{current_byte});
};
@@ -2551,7 +2551,7 @@ const WasmDumper = struct {
const name = data[fbs.pos..][0..name_len];
fbs.pos += name_len;
- const kind = std.meta.intToEnum(std.wasm.ExternalKind, try reader.readByte()) catch {
+ const kind = std.enums.fromInt(std.wasm.ExternalKind, try reader.readByte()) orelse {
return step.fail("invalid import kind", .{});
};
@@ -2613,7 +2613,7 @@ const WasmDumper = struct {
const name = data[fbs.pos..][0..name_len];
fbs.pos += name_len;
const kind_byte = try std.leb.readUleb128(u8, reader);
- const kind = std.meta.intToEnum(std.wasm.ExternalKind, kind_byte) catch {
+ const kind = std.enums.fromInt(std.wasm.ExternalKind, kind_byte) orelse {
return step.fail("invalid export kind value '{d}'", .{kind_byte});
};
const index = try std.leb.readUleb128(u32, reader);
@@ -2664,7 +2664,7 @@ const WasmDumper = struct {
fn parseDumpType(step: *Step, comptime E: type, reader: anytype, writer: anytype) !E {
const byte = try reader.readByte();
- const tag = std.meta.intToEnum(E, byte) catch {
+ const tag = std.enums.fromInt(E, byte) orelse {
return step.fail("invalid wasm type value '{d}'", .{byte});
};
try writer.print("type {s}\n", .{@tagName(tag)});
@@ -2683,7 +2683,7 @@ const WasmDumper = struct {
fn parseDumpInit(step: *Step, reader: anytype, writer: anytype) !void {
const byte = try reader.readByte();
- const opcode = std.meta.intToEnum(std.wasm.Opcode, byte) catch {
+ const opcode = std.enums.fromInt(std.wasm.Opcode, byte) orelse {
return step.fail("invalid wasm opcode '{d}'", .{byte});
};
switch (opcode) {
lib/std/json/static.zig
@@ -595,7 +595,7 @@ pub fn innerParseFromValue(
switch (source) {
.float => return error.InvalidEnumTag,
- .integer => |i| return std.meta.intToEnum(T, i),
+ .integer => |i| return std.enums.fromInt(T, i) orelse return error.InvalidEnumTag,
.number_string, .string => |s| return sliceToEnum(T, s),
else => return error.UnexpectedToken,
}
@@ -780,7 +780,7 @@ fn sliceToEnum(comptime T: type, slice: []const u8) !T {
// Check for a numeric value.
if (!isNumberFormattedLikeAnInteger(slice)) return error.InvalidEnumTag;
const n = std.fmt.parseInt(@typeInfo(T).@"enum".tag_type, slice, 10) catch return error.InvalidEnumTag;
- return std.meta.intToEnum(T, n);
+ return std.enums.fromInt(T, n) orelse return error.InvalidEnumTag;
}
fn fillDefaultStructValues(comptime T: type, r: *T, fields_seen: *[@typeInfo(T).@"struct".fields.len]bool) !void {
lib/std/enums.zig
@@ -8,6 +8,25 @@ const EnumField = std.builtin.Type.EnumField;
/// Increment this value when adding APIs that add single backwards branches.
const eval_branch_quota_cushion = 10;
+pub fn fromInt(comptime E: type, integer: anytype) ?E {
+ const enum_info = @typeInfo(E).@"enum";
+ if (!enum_info.is_exhaustive) {
+ if (std.math.cast(enum_info.tag_type, integer)) |tag| {
+ return @enumFromInt(tag);
+ }
+ return null;
+ }
+ // We don't directly iterate over the fields of E, as that
+ // would require an inline loop. Instead, we create an array of
+ // values that is comptime-know, but can be iterated at runtime
+ // without requiring an inline loop.
+ // This generates better machine code.
+ for (values(E)) |value| {
+ if (@intFromEnum(value) == integer) return @enumFromInt(integer);
+ }
+ return null;
+}
+
/// Returns a struct with a field matching each unique named enum element.
/// If the enum is extern and has multiple names for the same value, only
/// the first name is used. Each field is of type Data and has the provided
@@ -239,6 +258,30 @@ test nameCast {
try testing.expectEqual(B.b, nameCast(B, "b"));
}
+test fromInt {
+ const E1 = enum {
+ A,
+ };
+ const E2 = enum {
+ A,
+ B,
+ };
+ const E3 = enum(i8) { A, _ };
+
+ var zero: u8 = 0;
+ var one: u16 = 1;
+ _ = &zero;
+ _ = &one;
+ try testing.expect(fromInt(E1, zero).? == E1.A);
+ try testing.expect(fromInt(E2, one).? == E2.B);
+ try testing.expect(fromInt(E3, zero).? == E3.A);
+ try testing.expect(fromInt(E3, 127).? == @as(E3, @enumFromInt(127)));
+ try testing.expect(fromInt(E3, -128).? == @as(E3, @enumFromInt(-128)));
+ try testing.expectEqual(null, fromInt(E1, one));
+ try testing.expectEqual(null, fromInt(E3, 128));
+ try testing.expectEqual(null, fromInt(E3, -129));
+}
+
/// A set of enum elements, backed by a bitfield. If the enum
/// is exhaustive but not dense, a mapping will be constructed from enum values
/// to dense indices. This type does no dynamic allocation and
lib/std/meta.zig
@@ -857,58 +857,12 @@ test eql {
try testing.expect(!eql(CU{ .a = {} }, .b));
}
-test intToEnum {
- const E1 = enum {
- A,
- };
- const E2 = enum {
- A,
- B,
- };
- const E3 = enum(i8) { A, _ };
-
- var zero: u8 = 0;
- var one: u16 = 1;
- _ = &zero;
- _ = &one;
- try testing.expect(intToEnum(E1, zero) catch unreachable == E1.A);
- try testing.expect(intToEnum(E2, one) catch unreachable == E2.B);
- try testing.expect(intToEnum(E3, zero) catch unreachable == E3.A);
- try testing.expect(intToEnum(E3, 127) catch unreachable == @as(E3, @enumFromInt(127)));
- try testing.expect(intToEnum(E3, -128) catch unreachable == @as(E3, @enumFromInt(-128)));
- try testing.expectError(error.InvalidEnumTag, intToEnum(E1, one));
- try testing.expectError(error.InvalidEnumTag, intToEnum(E3, 128));
- try testing.expectError(error.InvalidEnumTag, intToEnum(E3, -129));
-}
-
+/// Deprecated: use `std.enums.fromInt` instead and handle null.
pub const IntToEnumError = error{InvalidEnumTag};
+/// Deprecated: use `std.enums.fromInt` instead and handle null instead of an error.
pub fn intToEnum(comptime EnumTag: type, tag_int: anytype) IntToEnumError!EnumTag {
- const enum_info = @typeInfo(EnumTag).@"enum";
-
- if (!enum_info.is_exhaustive) {
- if (std.math.cast(enum_info.tag_type, tag_int)) |tag| {
- return @as(EnumTag, @enumFromInt(tag));
- }
- return error.InvalidEnumTag;
- }
-
- // We don't directly iterate over the fields of EnumTag, as that
- // would require an inline loop. Instead, we create an array of
- // values that is comptime-know, but can be iterated at runtime
- // without requiring an inline loop. This generates better
- // machine code.
- const values = comptime blk: {
- var result: [enum_info.fields.len]enum_info.tag_type = undefined;
- for (&result, enum_info.fields) |*dst, src| {
- dst.* = src.value;
- }
- break :blk result;
- };
- for (values) |v| {
- if (v == tag_int) return @enumFromInt(tag_int);
- }
- return error.InvalidEnumTag;
+ return std.enums.fromInt(EnumTag, tag_int) orelse return error.InvalidEnumTag;
}
/// Given a type and a name, return the field index according to source order.
src/Package/Fetch/git.zig
@@ -313,7 +313,7 @@ pub const Repository = struct {
unused: u3,
type: u4,
} = @bitCast(std.fmt.parseUnsigned(u16, iterator.data[iterator.pos..mode_end], 8) catch return error.InvalidTree);
- const @"type" = std.meta.intToEnum(Entry.Type, mode.type) catch return error.InvalidTree;
+ const @"type" = std.enums.fromInt(Entry.Type, mode.type) orelse return error.InvalidTree;
const executable = switch (mode.permission) {
0 => if (@"type" == .file) return error.InvalidTree else false,
0o644 => if (@"type" != .file) return error.InvalidTree else false,
@@ -1144,7 +1144,7 @@ const EntryHeader = union(Type) {
const rest_len = if (initial.has_next) try readSizeVarInt(reader) else 0;
var uncompressed_length: u64 = initial.len;
uncompressed_length |= std.math.shlExact(u64, rest_len, 4) catch return error.InvalidFormat;
- const @"type" = std.meta.intToEnum(EntryHeader.Type, initial.type) catch return error.InvalidFormat;
+ const @"type" = std.enums.fromInt(EntryHeader.Type, initial.type) orelse return error.InvalidFormat;
return switch (@"type") {
inline .commit, .tree, .blob, .tag => |tag| @unionInit(EntryHeader, @tagName(tag), .{
.uncompressed_length = uncompressed_length,
src/Value.zig
@@ -3814,7 +3814,7 @@ pub fn interpret(val: Value, comptime T: type, pt: Zcu.PerThread) error{ OutOfMe
.@"enum" => switch (interpret_mode) {
.direct => {
const int = val.getUnsignedInt(zcu) orelse return error.TypeMismatch;
- return std.meta.intToEnum(T, int) catch error.TypeMismatch;
+ return std.enums.fromInt(T, int) orelse error.TypeMismatch;
},
.by_name => {
const field_index = ty.enumTagFieldIndex(val, zcu) orelse return error.TypeMismatch;
test/behavior/enum.zig
@@ -19,16 +19,16 @@ test "enum to int" {
try shouldEqual(Number.Four, 4);
}
-fn testIntToEnumEval(x: i32) !void {
- try expect(@as(IntToEnumNumber, @enumFromInt(x)) == IntToEnumNumber.Three);
+fn testEnumFromIntEval(x: i32) !void {
+ try expect(@as(EnumFromIntNumber, @enumFromInt(x)) == EnumFromIntNumber.Three);
}
-const IntToEnumNumber = enum { Zero, One, Two, Three, Four };
+const EnumFromIntNumber = enum { Zero, One, Two, Three, Four };
test "int to enum" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
- try testIntToEnumEval(3);
+ try testEnumFromIntEval(3);
}
const ValueCount1 = enum {