mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
std.meta.intToEnum -> std.enums.fromInt
Also use an optional as the return type instead of an error code.
This commit is contained in:
parent
a3693aae3a
commit
a365971a33
9 changed files with 64 additions and 67 deletions
|
|
@ -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";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue