╭ enums.zig ────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
1 //! This module contains utilities and data structures for working with enums. 2 3 const std = @import("std"); 4 const assert = std.debug.assert; 5 const testing = std.testing; 6 7 /// Increment this value when adding APIs that add single backwards branches. 8 const eval_branch_quota_cushion = 10; 9 10 pub fn fromInt(comptime E: type, integer: anytype) ?E { 11 const enum_info = @typeInfo(E).@"enum"; 12 if (enum_info.mode == .nonexhaustive) { 13 if (std.math.cast(enum_info.tag_type, integer)) |tag| { 14 return @fromBackingInt(@intCast(tag)); 15 } 16 return null; 17 } 18 // We don't directly iterate over the fields of E, as that 19 // would require an inline loop. Instead, we create an array of 20 // values that is comptime-know, but can be iterated at runtime 21 // without requiring an inline loop. 22 // This generates better machine code. 23 for (values(E)) |value| { 24 if (@backingInt(value) == integer) return value; 25 } 26 return null; 27 } 28 29 /// Returns a struct with a field matching each unique named enum element. 30 /// If the enum is extern and has multiple names for the same value, only 31 /// the first name is used. Each field is of type Data and has the provided 32 /// default, which may be undefined. 33 pub fn EnumFieldStruct(comptime E: type, comptime Data: type, comptime field_default: ?Data) type { 34 @setEvalBranchQuota(@typeInfo(E).@"enum".field_names.len + eval_branch_quota_cushion); 35 const default_ptr: ?*const anyopaque = if (field_default) |d| @ptrCast(&d) else null; 36 const field_names = @typeInfo(E).@"enum".field_names; 37 return @Struct(.auto, null, field_names, &@splat(Data), &@splat(.{ .default_value_ptr = default_ptr })); 38 } 39 40 /// Looks up the supplied field values in the given enum type. 41 /// The result array is in the same order as the input. 42 pub inline fn valuesFromFields(comptime E: type, comptime field_values: []const comptime_int) []const E { 43 comptime { 44 @setEvalBranchQuota(@typeInfo(E).@"enum".field_names.len + eval_branch_quota_cushion); 45 var result: [field_values.len]E = undefined; 46 for (&result, field_values) |*r, f_value| { 47 r.* = @fromBackingInt(@intCast(f_value)); 48 } 49 const final = result; 50 return &final; 51 } 52 } 53 54 /// Returns the set of all named values in the given enum, in 55 /// declaration order. 56 pub inline fn values(comptime E: type) []const E { 57 return comptime valuesFromFields(E, @typeInfo(E).@"enum".field_values); 58 } 59 60 /// A safe alternative to @tagName() for non-exhaustive enums that doesn't 61 /// panic when `e` has no tagged value. 62 /// Returns the tag name for `e` or null if no tag exists. 63 pub fn tagName(comptime E: type, e: E) ?[:0]const u8 { 64 const field_names = @typeInfo(E).@"enum".field_names; 65 const field_values = @typeInfo(E).@"enum".field_values; 66 @setEvalBranchQuota(field_names.len); 67 return inline for (field_names, field_values) |f_name, f_value| { 68 if (@backingInt(e) == f_value) break f_name; 69 } else null; 70 } 71 72 test tagName { 73 const E = enum(u8) { a, b, _ }; 74 try testing.expect(tagName(E, .a) != null); 75 try testing.expectEqualStrings("a", tagName(E, .a).?); 76 try testing.expect(tagName(E, @as(E, @fromBackingInt(@intCast(42)))) == null); 77 } 78 79 /// Determines the length of a direct-mapped enum array, indexed by 80 /// @intCast(usize, @intFromEnum(enum_value)). 81 /// If the enum is non-exhaustive, the resulting length will only be enough 82 /// to hold all explicit fields. 83 /// If the enum contains any fields with values that cannot be represented 84 /// by usize, a compile error is issued. The max_unused_slots parameter limits 85 /// the total number of items which have no matching enum key (holes in the enum 86 /// numbering). So for example, if an enum has values 1, 2, 5, and 6, max_unused_slots 87 /// must be at least 3, to allow unused slots 0, 3, and 4. 88 pub fn directEnumArrayLen(comptime E: type, comptime max_unused_slots: comptime_int) comptime_int { 89 var max_value: comptime_int = -1; 90 const max_usize: comptime_int = ~@as(usize, 0); 91 const info = @typeInfo(E).@"enum"; 92 for (info.field_names, info.field_values) |f_name, f_value| { 93 if (f_value < 0) { 94 @compileError("Cannot create a direct enum array for " ++ @typeName(E) ++ ", field ." ++ f_name ++ " has a negative value."); 95 } 96 if (f_value > max_value) { 97 if (f_value > max_usize) { 98 @compileError("Cannot create a direct enum array for " ++ @typeName(E) ++ ", field ." ++ f_name ++ " is larger than the max value of usize."); 99 } 100 max_value = f_value; 101 } 102 } 103 104 const unused_slots = max_value + 1 - info.field_names.len; 105 if (unused_slots > max_unused_slots) { 106 const unused_str = std.fmt.comptimePrint("{d}", .{unused_slots}); 107 const allowed_str = std.fmt.comptimePrint("{d}", .{max_unused_slots}); 108 @compileError("Cannot create a direct enum array for " ++ @typeName(E) ++ ". It would have " ++ unused_str ++ " unused slots, but only " ++ allowed_str ++ " are allowed."); 109 } 110 111 return max_value + 1; 112 } 113 114 /// Initializes an array of Data which can be indexed by 115 /// @intCast(usize, @intFromEnum(enum_value)). 116 /// If the enum is non-exhaustive, the resulting array will only be large enough 117 /// to hold all explicit fields. 118 /// If the enum contains any fields with values that cannot be represented 119 /// by usize, a compile error is issued. The max_unused_slots parameter limits 120 /// the total number of items which have no matching enum key (holes in the enum 121 /// numbering). So for example, if an enum has values 1, 2, 5, and 6, max_unused_slots 122 /// must be at least 3, to allow unused slots 0, 3, and 4. 123 /// The init_values parameter must be a struct with field names that match the enum values. 124 /// If the enum has multiple fields with the same value, the name of the first one must 125 /// be used. 126 pub fn directEnumArray( 127 comptime E: type, 128 comptime Data: type, 129 comptime max_unused_slots: comptime_int, 130 init_values: EnumFieldStruct(E, Data, null), 131 ) [directEnumArrayLen(E, max_unused_slots)]Data { 132 return directEnumArrayDefault(E, Data, null, max_unused_slots, init_values); 133 } 134 135 test directEnumArray { 136 const E = enum(i4) { a = 4, b = 6, c = 2 }; 137 var runtime_false: bool = false; 138 _ = &runtime_false; 139 const array = directEnumArray(E, bool, 4, .{ 140 .a = true, 141 .b = runtime_false, 142 .c = true, 143 }); 144 145 try testing.expectEqual([7]bool, @TypeOf(array)); 146 try testing.expectEqual(true, array[4]); 147 try testing.expectEqual(false, array[6]); 148 try testing.expectEqual(true, array[2]); 149 } 150 151 /// Initializes an array of Data which can be indexed by 152 /// @intCast(usize, @intFromEnum(enum_value)). The enum must be exhaustive. 153 /// If the enum contains any fields with values that cannot be represented 154 /// by usize, a compile error is issued. The max_unused_slots parameter limits 155 /// the total number of items which have no matching enum key (holes in the enum 156 /// numbering). So for example, if an enum has values 1, 2, 5, and 6, max_unused_slots 157 /// must be at least 3, to allow unused slots 0, 3, and 4. 158 /// The init_values parameter must be a struct with field names that match the enum values. 159 /// If the enum has multiple fields with the same value, the name of the first one must 160 /// be used. 161 pub fn directEnumArrayDefault( 162 comptime E: type, 163 comptime Data: type, 164 comptime default: ?Data, 165 comptime max_unused_slots: comptime_int, 166 init_values: EnumFieldStruct(E, Data, default), 167 ) [directEnumArrayLen(E, max_unused_slots)]Data { 168 const len = comptime directEnumArrayLen(E, max_unused_slots); 169 var result: [len]Data = @splat(default orelse undefined); 170 inline for (@typeInfo(@TypeOf(init_values)).@"struct".field_names) |f_name| { 171 const enum_value = @field(E, f_name); 172 const index = @as(usize, @intCast(@backingInt(enum_value))); 173 result[index] = @field(init_values, f_name); 174 } 175 return result; 176 } 177 178 test directEnumArrayDefault { 179 const E = enum(i4) { a = 4, b = 6, c = 2 }; 180 var runtime_false: bool = false; 181 _ = &runtime_false; 182 const array = directEnumArrayDefault(E, bool, false, 4, .{ 183 .a = true, 184 .b = runtime_false, 185 }); 186 187 try testing.expectEqual([7]bool, @TypeOf(array)); 188 try testing.expectEqual(true, array[4]); 189 try testing.expectEqual(false, array[6]); 190 try testing.expectEqual(false, array[2]); 191 } 192 193 test "directEnumArrayDefault slice" { 194 const E = enum(i4) { a = 4, b = 6, c = 2 }; 195 var runtime_b = "b"; 196 _ = &runtime_b; 197 const array = directEnumArrayDefault(E, []const u8, "default", 4, .{ 198 .a = "a", 199 .b = runtime_b, 200 }); 201 202 try testing.expectEqual([7][]const u8, @TypeOf(array)); 203 try testing.expectEqualSlices(u8, "a", array[4]); 204 try testing.expectEqualSlices(u8, "b", array[6]); 205 try testing.expectEqualSlices(u8, "default", array[2]); 206 } 207 208 test fromInt { 209 const E1 = enum { 210 A, 211 }; 212 const E2 = enum { 213 A, 214 B, 215 }; 216 const E3 = enum(i8) { A, _ }; 217 const E4 = enum(u8) { A }; 218 219 var zero: u8 = 0; 220 var one: u16 = 1; 221 _ = &zero; 222 _ = &one; 223 try testing.expect(fromInt(E1, zero).? == E1.A); 224 try testing.expect(fromInt(E2, one).? == E2.B); 225 try testing.expect(fromInt(E3, zero).? == E3.A); 226 try testing.expect(fromInt(E3, 127).? == @as(E3, @fromBackingInt(@intCast(127)))); 227 try testing.expect(fromInt(E3, -128).? == @as(E3, @fromBackingInt(@intCast(-128)))); 228 try testing.expectEqual(null, fromInt(E1, one)); 229 try testing.expectEqual(null, fromInt(E3, 128)); 230 try testing.expectEqual(null, fromInt(E3, -129)); 231 232 // `fromInt` used to produce a compiler error instead of `null` if trying to convert an integer 233 // that wasn't out of range, but also wasn't a valid value. 234 try testing.expectEqual(null, fromInt(E4, 1)); 235 } 236 237 /// A set of enum elements, backed by a bitfield. If the enum 238 /// is exhaustive but not dense, a mapping will be constructed from enum values 239 /// to dense indices. This type does no dynamic allocation and 240 /// can be copied by value. 241 pub fn EnumSet(comptime E: type) type { 242 return struct { 243 const Self = @This(); 244 245 /// The indexing rules for converting between keys and indices. 246 pub const Indexer = EnumIndexer(E); 247 /// The element type for this set. 248 pub const Key = Indexer.Key; 249 250 const BitSet = std.bit_set.Static(Indexer.count); 251 252 /// The maximum number of items in this set. 253 pub const len = Indexer.count; 254 255 bits: BitSet = .empty, 256 257 /// Initializes the set using a struct of bools 258 pub fn init(init_values: EnumFieldStruct(E, bool, false)) Self { 259 @setEvalBranchQuota(2 * @typeInfo(E).@"enum".field_names.len); 260 var result: Self = .{}; 261 if (@typeInfo(E).@"enum".mode == .exhaustive) { 262 inline for (0..Self.len) |i| { 263 const key = comptime Indexer.keyForIndex(i); 264 const tag = @tagName(key); 265 if (@field(init_values, tag)) { 266 result.bits.set(i); 267 } 268 } 269 } else { 270 inline for (@typeInfo(E).@"enum".field_names) |field_name| { 271 const key = @field(E, field_name); 272 if (@field(init_values, field_name)) { 273 const i = comptime Indexer.indexOf(key); 274 result.bits.set(i); 275 } 276 } 277 } 278 return result; 279 } 280 281 /// A set containing no keys. 282 pub const empty: Self = .{ .bits = .empty }; 283 284 /// A set containing all possible keys. 285 pub const full: Self = .{ .bits = .full }; 286 287 /// Returns a set containing multiple keys. 288 pub fn initMany(keys: []const Key) Self { 289 var set: Self = .empty; 290 for (keys) |key| set.insert(key); 291 return set; 292 } 293 294 /// Returns a set containing a single key. 295 pub fn initOne(key: Key) Self { 296 return initMany(&[_]Key{key}); 297 } 298 299 /// Returns the number of keys in the set. 300 pub fn count(self: Self) usize { 301 return self.bits.count(); 302 } 303 304 /// Checks if a key is in the set. 305 pub fn contains(self: Self, key: Key) bool { 306 return self.bits.isSet(Indexer.indexOf(key)); 307 } 308 309 /// Puts a key in the set. 310 pub fn insert(self: *Self, key: Key) void { 311 self.bits.set(Indexer.indexOf(key)); 312 } 313 314 /// Removes a key from the set. 315 pub fn remove(self: *Self, key: Key) void { 316 self.bits.unset(Indexer.indexOf(key)); 317 } 318 319 /// Changes the presence of a key in the set to match the passed bool. 320 pub fn setPresent(self: *Self, key: Key, present: bool) void { 321 self.bits.setValue(Indexer.indexOf(key), present); 322 } 323 324 /// Toggles the presence of a key in the set. If the key is in 325 /// the set, removes it. Otherwise adds it. 326 pub fn toggle(self: *Self, key: Key) void { 327 self.bits.toggle(Indexer.indexOf(key)); 328 } 329 330 /// Toggles the presence of all keys in the passed set. 331 pub fn toggleSet(self: *Self, other: Self) void { 332 self.bits.toggleSet(other.bits); 333 } 334 335 /// Toggles all possible keys in the set. 336 pub fn toggleAll(self: *Self) void { 337 self.bits.toggleAll(); 338 } 339 340 /// Adds all keys in the passed set to this set. 341 pub fn setUnion(self: *Self, other: Self) void { 342 self.bits.setUnion(other.bits); 343 } 344 345 /// Removes all keys which are not in the passed set. 346 pub fn setIntersection(self: *Self, other: Self) void { 347 self.bits.setIntersection(other.bits); 348 } 349 350 /// Returns true iff both sets have the same keys. 351 pub fn eql(self: Self, other: Self) bool { 352 return self.bits.eql(other.bits); 353 } 354 355 /// Returns true iff all the keys in this set are 356 /// in the other set. The other set may have keys 357 /// not found in this set. 358 pub fn subsetOf(self: Self, other: Self) bool { 359 return self.bits.subsetOf(other.bits); 360 } 361 362 /// Returns true iff this set contains all the keys 363 /// in the other set. This set may have keys not 364 /// found in the other set. 365 pub fn supersetOf(self: Self, other: Self) bool { 366 return self.bits.supersetOf(other.bits); 367 } 368 369 /// Returns a set with all the keys not in this set. 370 pub fn complement(self: Self) Self { 371 return .{ .bits = self.bits.complement() }; 372 } 373 374 /// Returns a set with keys that are in either this 375 /// set or the other set. 376 pub fn unionWith(self: Self, other: Self) Self { 377 return .{ .bits = self.bits.unionWith(other.bits) }; 378 } 379 380 /// Returns a set with keys that are in both this 381 /// set and the other set. 382 pub fn intersectWith(self: Self, other: Self) Self { 383 return .{ .bits = self.bits.intersectWith(other.bits) }; 384 } 385 386 /// Returns a set with keys that are in either this 387 /// set or the other set, but not both. 388 pub fn xorWith(self: Self, other: Self) Self { 389 return .{ .bits = self.bits.xorWith(other.bits) }; 390 } 391 392 /// Returns a set with keys that are in this set 393 /// except for keys in the other set. 394 pub fn differenceWith(self: Self, other: Self) Self { 395 return .{ .bits = self.bits.differenceWith(other.bits) }; 396 } 397 398 /// Returns an iterator over this set, which iterates in 399 /// index order. Modifications to the set during iteration 400 /// may or may not be observed by the iterator, but will 401 /// not invalidate it. 402 pub fn iterator(self: *const Self) Iterator { 403 return .{ .inner = self.bits.iterator(.{}) }; 404 } 405 406 pub const Iterator = struct { 407 inner: BitSet.Iterator(.{}), 408 409 pub fn next(self: *Iterator) ?Key { 410 return if (self.inner.next()) |index| 411 Indexer.keyForIndex(index) 412 else 413 null; 414 } 415 }; 416 }; 417 } 418 419 /// A map keyed by an enum, backed by a bitfield and a dense array. 420 /// If the enum is exhaustive but not dense, a mapping will be constructed from 421 /// enum values to dense indices. This type does no dynamic 422 /// allocation and can be copied by value. 423 /// 424 /// Default initialization is deprecated; use .empty instead. 425 pub fn EnumMap(comptime E: type, comptime V: type) type { 426 return struct { 427 const Self = @This(); 428 429 /// The index mapping for this map 430 pub const Indexer = EnumIndexer(E); 431 /// The key type used to index this map 432 pub const Key = Indexer.Key; 433 /// The value type stored in this map 434 pub const Value = V; 435 /// The number of possible keys in the map 436 pub const len = Indexer.count; 437 438 const BitSet = std.bit_set.Static(Indexer.count); 439 440 /// Bits determining whether items are in the map 441 bits: BitSet = .empty, 442 /// Values of items in the map. If the associated 443 /// bit is zero, the value is undefined. 444 values: [Indexer.count]Value = undefined, 445 446 pub const empty: Self = .{ 447 .bits = .empty, 448 .values = undefined, 449 }; 450 451 /// Initializes the map using a sparse struct of optionals 452 pub fn init(init_values: EnumFieldStruct(E, ?Value, @as(?Value, null))) Self { 453 @setEvalBranchQuota(2 * @typeInfo(E).@"enum".field_names.len); 454 var result: Self = .{}; 455 if (@typeInfo(E).@"enum".mode == .exhaustive) { 456 inline for (0..Self.len) |i| { 457 const key = comptime Indexer.keyForIndex(i); 458 const tag = @tagName(key); 459 if (@field(init_values, tag)) |*v| { 460 result.bits.set(i); 461 result.values[i] = v.*; 462 } 463 } 464 } else { 465 inline for (@typeInfo(E).@"enum".field_names) |field_name| { 466 const key = @field(E, field_name); 467 if (@field(init_values, field_name)) |*v| { 468 const i = comptime Indexer.indexOf(key); 469 result.bits.set(i); 470 result.values[i] = v.*; 471 } 472 } 473 } 474 return result; 475 } 476 477 /// Initializes a full mapping with all keys set to value. 478 /// Consider using EnumArray instead if the map will remain full. 479 pub fn initFull(value: Value) Self { 480 return .{ 481 .bits = .full, 482 .values = @splat(value), 483 }; 484 } 485 486 /// Initializes a full mapping with supplied values. 487 /// Consider using EnumArray instead if the map will remain full. 488 pub fn initFullWith(init_values: EnumFieldStruct(E, Value, null)) Self { 489 return initFullWithDefault(null, init_values); 490 } 491 492 /// Initializes a full mapping with a provided default. 493 /// Consider using EnumArray instead if the map will remain full. 494 pub fn initFullWithDefault(comptime default: ?Value, init_values: EnumFieldStruct(E, Value, default)) Self { 495 @setEvalBranchQuota(2 * @typeInfo(E).@"enum".field_names.len); 496 var result: Self = .{ 497 .bits = .full, 498 .values = undefined, 499 }; 500 inline for (0..Self.len) |i| { 501 const key = comptime Indexer.keyForIndex(i); 502 const tag = @tagName(key); 503 result.values[i] = @field(init_values, tag); 504 } 505 return result; 506 } 507 508 /// The number of items in the map. 509 pub fn count(self: *const Self) usize { 510 return self.bits.count(); 511 } 512 513 /// Checks if the map contains an item. 514 pub fn contains(self: *const Self, key: Key) bool { 515 return self.bits.isSet(Indexer.indexOf(key)); 516 } 517 518 /// Gets the value associated with a key. 519 /// If the key is not in the map, returns null. 520 pub fn get(self: *const Self, key: Key) ?Value { 521 const index = Indexer.indexOf(key); 522 return if (self.bits.isSet(index)) self.values[index] else null; 523 } 524 525 /// Gets the value associated with a key, which must 526 /// exist in the map. 527 pub fn getAssertContains(self: *const Self, key: Key) Value { 528 const index = Indexer.indexOf(key); 529 assert(self.bits.isSet(index)); 530 return self.values[index]; 531 } 532 533 /// Gets the address of the value associated with a key. 534 /// If the key is not in the map, returns null. 535 pub fn getPtr(self: *Self, key: Key) ?*Value { 536 const index = Indexer.indexOf(key); 537 return if (self.bits.isSet(index)) &self.values[index] else null; 538 } 539 540 /// Gets the address of the const value associated with a key. 541 /// If the key is not in the map, returns null. 542 pub fn getPtrConst(self: *const Self, key: Key) ?*const Value { 543 const index = Indexer.indexOf(key); 544 return if (self.bits.isSet(index)) &self.values[index] else null; 545 } 546 547 /// Gets the address of the value associated with a key. 548 /// The key must be present in the map. 549 pub fn getPtrAssertContains(self: *Self, key: Key) *Value { 550 const index = Indexer.indexOf(key); 551 assert(self.bits.isSet(index)); 552 return &self.values[index]; 553 } 554 555 /// Gets the address of the const value associated with a key. 556 /// The key must be present in the map. 557 pub fn getPtrConstAssertContains(self: *const Self, key: Key) *const Value { 558 const index = Indexer.indexOf(key); 559 assert(self.bits.isSet(index)); 560 return &self.values[index]; 561 } 562 563 /// Adds the key to the map with the supplied value. 564 /// If the key is already in the map, overwrites the value. 565 pub fn put(self: *Self, key: Key, value: Value) void { 566 const index = Indexer.indexOf(key); 567 self.bits.set(index); 568 self.values[index] = value; 569 } 570 571 /// Adds the key to the map with an undefined value. 572 /// If the key is already in the map, the value becomes undefined. 573 /// A pointer to the value is returned, which should be 574 /// used to initialize the value. 575 pub fn putUninitialized(self: *Self, key: Key) *Value { 576 const index = Indexer.indexOf(key); 577 self.bits.set(index); 578 self.values[index] = undefined; 579 return &self.values[index]; 580 } 581 582 /// Sets the value associated with the key in the map, 583 /// and returns the old value. If the key was not in 584 /// the map, returns null. 585 pub fn fetchPut(self: *Self, key: Key, value: Value) ?Value { 586 const index = Indexer.indexOf(key); 587 const result: ?Value = if (self.bits.isSet(index)) self.values[index] else null; 588 self.bits.set(index); 589 self.values[index] = value; 590 return result; 591 } 592 593 /// Removes a key from the map. If the key was not in the map, 594 /// does nothing. 595 pub fn remove(self: *Self, key: Key) void { 596 const index = Indexer.indexOf(key); 597 self.bits.unset(index); 598 self.values[index] = undefined; 599 } 600 601 /// Removes a key from the map, and returns the old value. 602 /// If the key was not in the map, returns null. 603 pub fn fetchRemove(self: *Self, key: Key) ?Value { 604 const index = Indexer.indexOf(key); 605 const result: ?Value = if (self.bits.isSet(index)) self.values[index] else null; 606 self.bits.unset(index); 607 self.values[index] = undefined; 608 return result; 609 } 610 611 /// Returns an iterator over the map, which visits items in index order. 612 /// Modifications to the underlying map may or may not be observed by 613 /// the iterator, but will not invalidate it. 614 pub fn iterator(self: *Self) Iterator { 615 return .{ 616 .inner = self.bits.iterator(.{}), 617 .values = &self.values, 618 }; 619 } 620 621 /// An entry in the map. 622 pub const Entry = struct { 623 /// The key associated with this entry. 624 /// Modifying this key will not change the map. 625 key: Key, 626 627 /// A pointer to the value in the map associated 628 /// with this key. Modifications through this 629 /// pointer will modify the underlying data. 630 value: *Value, 631 }; 632 633 pub const Iterator = struct { 634 inner: BitSet.Iterator(.{}), 635 values: *[Indexer.count]Value, 636 637 pub fn next(self: *Iterator) ?Entry { 638 return if (self.inner.next()) |index| 639 Entry{ 640 .key = Indexer.keyForIndex(index), 641 .value = &self.values[index], 642 } 643 else 644 null; 645 } 646 }; 647 }; 648 } 649 650 test EnumMap { 651 const Ball = enum { red, green, blue }; 652 653 const none: EnumMap(Ball, u8) = .empty; 654 try testing.expectEqual(0, none.count()); 655 656 const some: EnumMap(Ball, u8) = .init(.{ 657 .green = 0xff, 658 .blue = 0x80, 659 }); 660 try testing.expectEqual(2, some.count()); 661 try testing.expectEqual(null, some.get(.red)); 662 try testing.expectEqual(0xff, some.get(.green)); 663 try testing.expectEqual(0x80, some.get(.blue)); 664 665 const all: EnumMap(Ball, u8) = .initFull(0); 666 try testing.expectEqual(3, all.count()); 667 } 668 669 /// A multiset of enum elements up to a count of usize. Backed 670 /// by an EnumArray. This type does no dynamic allocation and can 671 /// be copied by value. 672 pub fn EnumMultiset(comptime E: type) type { 673 return BoundedEnumMultiset(E, usize); 674 } 675 676 /// A multiset of enum elements up to CountSize. Backed by an 677 /// EnumArray. This type does no dynamic allocation and can be 678 /// copied by value. 679 pub fn BoundedEnumMultiset(comptime E: type, comptime CountSize: type) type { 680 return struct { 681 const Self = @This(); 682 683 counts: EnumArray(E, CountSize), 684 685 /// Initializes the multiset using a struct of counts. 686 pub fn init(init_counts: EnumFieldStruct(E, CountSize, 0)) Self { 687 @setEvalBranchQuota(2 * @typeInfo(E).@"enum".field_names.len); 688 var self = initWithCount(0); 689 const info = @typeInfo(E).@"enum"; 690 inline for (info.field_names, info.field_values) |field_name, field_value| { 691 const c = @field(init_counts, field_name); 692 const key: E = @fromBackingInt(@intCast(field_value)); 693 self.counts.set(key, c); 694 } 695 return self; 696 } 697 698 /// A multiset with a count of zero. 699 pub const empty: Self = .initWithCount(0); 700 701 /// Initializes the multiset with all keys at the 702 /// same count. 703 pub fn initWithCount(comptime c: CountSize) Self { 704 return .{ 705 .counts = .initDefault(c, .{}), 706 }; 707 } 708 709 /// Returns the total number of key counts in the multiset. 710 pub fn count(self: Self) usize { 711 var sum: usize = 0; 712 for (self.counts.values) |c| { 713 sum += c; 714 } 715 return sum; 716 } 717 718 /// Checks if at least one key in multiset. 719 pub fn contains(self: Self, key: E) bool { 720 return self.counts.get(key) > 0; 721 } 722 723 /// Removes all instance of a key from multiset. Same as 724 /// setCount(key, 0). 725 pub fn removeAll(self: *Self, key: E) void { 726 return self.counts.set(key, 0); 727 } 728 729 /// Increases the key count by given amount. Caller asserts 730 /// operation will not overflow. 731 pub fn addAssertSafe(self: *Self, key: E, c: CountSize) void { 732 self.counts.getPtr(key).* += c; 733 } 734 735 /// Increases the key count by given amount. 736 pub fn add(self: *Self, key: E, c: CountSize) error{Overflow}!void { 737 self.counts.set(key, try std.math.add(CountSize, self.counts.get(key), c)); 738 } 739 740 /// Decreases the key count by given amount. If amount is 741 /// greater than the number of keys in multset, then key count 742 /// will be set to zero. 743 pub fn remove(self: *Self, key: E, c: CountSize) void { 744 self.counts.getPtr(key).* -= @min(self.getCount(key), c); 745 } 746 747 /// Returns the count for a key. 748 pub fn getCount(self: Self, key: E) CountSize { 749 return self.counts.get(key); 750 } 751 752 /// Set the count for a key. 753 pub fn setCount(self: *Self, key: E, c: CountSize) void { 754 self.counts.set(key, c); 755 } 756 757 /// Increases the all key counts by given multiset. Caller 758 /// asserts operation will not overflow any key. 759 pub fn addSetAssertSafe(self: *Self, other: Self) void { 760 inline for (@typeInfo(E).@"enum".field_values) |field_value| { 761 const key = @as(E, @fromBackingInt(@intCast(field_value))); 762 self.addAssertSafe(key, other.getCount(key)); 763 } 764 } 765 766 /// Increases the all key counts by given multiset. 767 pub fn addSet(self: *Self, other: Self) error{Overflow}!void { 768 inline for (@typeInfo(E).@"enum".field_values) |field_value| { 769 const key = @as(E, @fromBackingInt(@intCast(field_value))); 770 try self.add(key, other.getCount(key)); 771 } 772 } 773 774 /// Decreases the all key counts by given multiset. If 775 /// the given multiset has more key counts than this, 776 /// then that key will have a key count of zero. 777 pub fn removeSet(self: *Self, other: Self) void { 778 inline for (@typeInfo(E).@"enum".field_values) |field_value| { 779 const key = @as(E, @fromBackingInt(@intCast(field_value))); 780 self.remove(key, other.getCount(key)); 781 } 782 } 783 784 /// Returns true iff all key counts are the same as 785 /// given multiset. 786 pub fn eql(self: Self, other: Self) bool { 787 inline for (@typeInfo(E).@"enum".field_values) |field_value| { 788 const key = @as(E, @fromBackingInt(@intCast(field_value))); 789 if (self.getCount(key) != other.getCount(key)) { 790 return false; 791 } 792 } 793 return true; 794 } 795 796 /// Returns true iff all key counts less than or 797 /// equal to the given multiset. 798 pub fn subsetOf(self: Self, other: Self) bool { 799 inline for (@typeInfo(E).@"enum".field_values) |field_value| { 800 const key = @as(E, @fromBackingInt(@intCast(field_value))); 801 if (self.getCount(key) > other.getCount(key)) { 802 return false; 803 } 804 } 805 return true; 806 } 807 808 /// Returns true iff all key counts greater than or 809 /// equal to the given multiset. 810 pub fn supersetOf(self: Self, other: Self) bool { 811 inline for (@typeInfo(E).@"enum".field_values) |field_value| { 812 const key = @as(E, @fromBackingInt(@intCast(field_value))); 813 if (self.getCount(key) < other.getCount(key)) { 814 return false; 815 } 816 } 817 return true; 818 } 819 820 /// Returns a multiset with the total key count of this 821 /// multiset and the other multiset. Caller asserts 822 /// operation will not overflow any key. 823 pub fn plusAssertSafe(self: Self, other: Self) Self { 824 var result = self; 825 result.addSetAssertSafe(other); 826 return result; 827 } 828 829 /// Returns a multiset with the total key count of this 830 /// multiset and the other multiset. 831 pub fn plus(self: Self, other: Self) error{Overflow}!Self { 832 var result = self; 833 try result.addSet(other); 834 return result; 835 } 836 837 /// Returns a multiset with the key count of this 838 /// multiset minus the corresponding key count in the 839 /// other multiset. If the other multiset contains 840 /// more key count than this set, that key will have 841 /// a count of zero. 842 pub fn minus(self: Self, other: Self) Self { 843 var result = self; 844 result.removeSet(other); 845 return result; 846 } 847 848 pub const Entry = EnumArray(E, CountSize).Entry; 849 pub const Iterator = EnumArray(E, CountSize).Iterator; 850 851 /// Returns an iterator over this multiset. Keys with zero 852 /// counts are included. Modifications to the set during 853 /// iteration may or may not be observed by the iterator, 854 /// but will not invalidate it. 855 pub fn iterator(self: *Self) Iterator { 856 return self.counts.iterator(); 857 } 858 }; 859 } 860 861 test EnumMultiset { 862 const Ball = enum { red, green, blue }; 863 864 const empty = EnumMultiset(Ball).empty; 865 const r0_g1_b2 = EnumMultiset(Ball).init(.{ 866 .red = 0, 867 .green = 1, 868 .blue = 2, 869 }); 870 const ten_of_each = EnumMultiset(Ball).initWithCount(10); 871 872 try testing.expectEqual(empty.count(), 0); 873 try testing.expectEqual(r0_g1_b2.count(), 3); 874 try testing.expectEqual(ten_of_each.count(), 30); 875 876 try testing.expect(!empty.contains(.red)); 877 try testing.expect(!empty.contains(.green)); 878 try testing.expect(!empty.contains(.blue)); 879 880 try testing.expect(!r0_g1_b2.contains(.red)); 881 try testing.expect(r0_g1_b2.contains(.green)); 882 try testing.expect(r0_g1_b2.contains(.blue)); 883 884 try testing.expect(ten_of_each.contains(.red)); 885 try testing.expect(ten_of_each.contains(.green)); 886 try testing.expect(ten_of_each.contains(.blue)); 887 888 { 889 var copy = ten_of_each; 890 copy.removeAll(.red); 891 try testing.expect(!copy.contains(.red)); 892 893 // removeAll second time does nothing 894 copy.removeAll(.red); 895 try testing.expect(!copy.contains(.red)); 896 } 897 898 { 899 var copy = ten_of_each; 900 copy.addAssertSafe(.red, 6); 901 try testing.expectEqual(copy.getCount(.red), 16); 902 } 903 904 { 905 var copy = ten_of_each; 906 try copy.add(.red, 6); 907 try testing.expectEqual(copy.getCount(.red), 16); 908 909 try testing.expectError(error.Overflow, copy.add(.red, std.math.maxInt(usize))); 910 } 911 912 { 913 var copy = ten_of_each; 914 copy.remove(.red, 4); 915 try testing.expectEqual(copy.getCount(.red), 6); 916 917 // subtracting more it contains does not underflow 918 copy.remove(.green, 14); 919 try testing.expectEqual(copy.getCount(.green), 0); 920 } 921 922 try testing.expectEqual(empty.getCount(.green), 0); 923 try testing.expectEqual(r0_g1_b2.getCount(.green), 1); 924 try testing.expectEqual(ten_of_each.getCount(.green), 10); 925 926 { 927 var copy = empty; 928 copy.setCount(.red, 6); 929 try testing.expectEqual(copy.getCount(.red), 6); 930 } 931 932 { 933 var copy = r0_g1_b2; 934 copy.addSetAssertSafe(ten_of_each); 935 try testing.expectEqual(copy.getCount(.red), 10); 936 try testing.expectEqual(copy.getCount(.green), 11); 937 try testing.expectEqual(copy.getCount(.blue), 12); 938 } 939 940 { 941 var copy = r0_g1_b2; 942 try copy.addSet(ten_of_each); 943 try testing.expectEqual(copy.getCount(.red), 10); 944 try testing.expectEqual(copy.getCount(.green), 11); 945 try testing.expectEqual(copy.getCount(.blue), 12); 946 947 const full = EnumMultiset(Ball).initWithCount(std.math.maxInt(usize)); 948 try testing.expectError(error.Overflow, copy.addSet(full)); 949 } 950 951 { 952 var copy = ten_of_each; 953 copy.removeSet(r0_g1_b2); 954 try testing.expectEqual(copy.getCount(.red), 10); 955 try testing.expectEqual(copy.getCount(.green), 9); 956 try testing.expectEqual(copy.getCount(.blue), 8); 957 958 copy.removeSet(ten_of_each); 959 try testing.expectEqual(copy.getCount(.red), 0); 960 try testing.expectEqual(copy.getCount(.green), 0); 961 try testing.expectEqual(copy.getCount(.blue), 0); 962 } 963 964 try testing.expect(empty.eql(empty)); 965 try testing.expect(r0_g1_b2.eql(r0_g1_b2)); 966 try testing.expect(ten_of_each.eql(ten_of_each)); 967 try testing.expect(!empty.eql(r0_g1_b2)); 968 try testing.expect(!r0_g1_b2.eql(ten_of_each)); 969 try testing.expect(!ten_of_each.eql(empty)); 970 971 try testing.expect(empty.subsetOf(empty)); 972 try testing.expect(r0_g1_b2.subsetOf(r0_g1_b2)); 973 try testing.expect(empty.subsetOf(r0_g1_b2)); 974 try testing.expect(r0_g1_b2.subsetOf(ten_of_each)); 975 try testing.expect(!ten_of_each.subsetOf(r0_g1_b2)); 976 try testing.expect(!r0_g1_b2.subsetOf(empty)); 977 978 try testing.expect(empty.supersetOf(empty)); 979 try testing.expect(r0_g1_b2.supersetOf(r0_g1_b2)); 980 try testing.expect(r0_g1_b2.supersetOf(empty)); 981 try testing.expect(ten_of_each.supersetOf(r0_g1_b2)); 982 try testing.expect(!r0_g1_b2.supersetOf(ten_of_each)); 983 try testing.expect(!empty.supersetOf(r0_g1_b2)); 984 985 { 986 // with multisets it could be the case where two 987 // multisets are neither subset nor superset of each 988 // other. 989 990 const r10 = EnumMultiset(Ball).init(.{ 991 .red = 10, 992 }); 993 const b10 = EnumMultiset(Ball).init(.{ 994 .blue = 10, 995 }); 996 997 try testing.expect(!r10.subsetOf(b10)); 998 try testing.expect(!b10.subsetOf(r10)); 999 try testing.expect(!r10.supersetOf(b10)); 1000 try testing.expect(!b10.supersetOf(r10)); 1001 } 1002 1003 { 1004 const result = r0_g1_b2.plusAssertSafe(ten_of_each); 1005 try testing.expectEqual(result.getCount(.red), 10); 1006 try testing.expectEqual(result.getCount(.green), 11); 1007 try testing.expectEqual(result.getCount(.blue), 12); 1008 } 1009 1010 { 1011 const result = try r0_g1_b2.plus(ten_of_each); 1012 try testing.expectEqual(result.getCount(.red), 10); 1013 try testing.expectEqual(result.getCount(.green), 11); 1014 try testing.expectEqual(result.getCount(.blue), 12); 1015 1016 const full = EnumMultiset(Ball).initWithCount(std.math.maxInt(usize)); 1017 try testing.expectError(error.Overflow, result.plus(full)); 1018 } 1019 1020 { 1021 const result = ten_of_each.minus(r0_g1_b2); 1022 try testing.expectEqual(result.getCount(.red), 10); 1023 try testing.expectEqual(result.getCount(.green), 9); 1024 try testing.expectEqual(result.getCount(.blue), 8); 1025 } 1026 1027 { 1028 const result = ten_of_each.minus(r0_g1_b2).minus(ten_of_each); 1029 try testing.expectEqual(result.getCount(.red), 0); 1030 try testing.expectEqual(result.getCount(.green), 0); 1031 try testing.expectEqual(result.getCount(.blue), 0); 1032 } 1033 1034 { 1035 var copy = empty; 1036 var it = copy.iterator(); 1037 var entry = it.next().?; 1038 try testing.expectEqual(entry.key, .red); 1039 try testing.expectEqual(entry.value.*, 0); 1040 entry = it.next().?; 1041 try testing.expectEqual(entry.key, .green); 1042 try testing.expectEqual(entry.value.*, 0); 1043 entry = it.next().?; 1044 try testing.expectEqual(entry.key, .blue); 1045 try testing.expectEqual(entry.value.*, 0); 1046 try testing.expectEqual(it.next(), null); 1047 } 1048 1049 { 1050 var copy = r0_g1_b2; 1051 var it = copy.iterator(); 1052 var entry = it.next().?; 1053 try testing.expectEqual(entry.key, .red); 1054 try testing.expectEqual(entry.value.*, 0); 1055 entry = it.next().?; 1056 try testing.expectEqual(entry.key, .green); 1057 try testing.expectEqual(entry.value.*, 1); 1058 entry = it.next().?; 1059 try testing.expectEqual(entry.key, .blue); 1060 try testing.expectEqual(entry.value.*, 2); 1061 try testing.expectEqual(it.next(), null); 1062 } 1063 } 1064 1065 /// An array keyed by an enum, backed by a dense array. 1066 /// If the enum is not dense, a mapping will be constructed from 1067 /// enum values to dense indices. This type does no dynamic 1068 /// allocation and can be copied by value. 1069 pub fn EnumArray(comptime E: type, comptime V: type) type { 1070 return struct { 1071 const Self = @This(); 1072 1073 /// The index mapping for this map 1074 pub const Indexer = EnumIndexer(E); 1075 /// The key type used to index this map 1076 pub const Key = Indexer.Key; 1077 /// The value type stored in this map 1078 pub const Value = V; 1079 /// The number of possible keys in the map 1080 pub const len = Indexer.count; 1081 1082 values: [Indexer.count]Value, 1083 1084 pub fn init(init_values: EnumFieldStruct(E, Value, null)) Self { 1085 return initDefault(null, init_values); 1086 } 1087 1088 /// Initializes values in the enum array, with the specified default. 1089 pub fn initDefault(comptime default: ?Value, init_values: EnumFieldStruct(E, Value, default)) Self { 1090 @setEvalBranchQuota(2 * @typeInfo(E).@"enum".field_names.len); 1091 var result: Self = .{ .values = undefined }; 1092 inline for (0..Self.len) |i| { 1093 const key = comptime Indexer.keyForIndex(i); 1094 const tag = @tagName(key); 1095 result.values[i] = @field(init_values, tag); 1096 } 1097 return result; 1098 } 1099 1100 pub fn initUndefined() Self { 1101 return Self{ .values = undefined }; 1102 } 1103 1104 pub fn initFill(v: Value) Self { 1105 var self: Self = undefined; 1106 @memset(&self.values, v); 1107 return self; 1108 } 1109 1110 /// Returns the value in the array associated with a key. 1111 pub fn get(self: Self, key: Key) Value { 1112 return self.values[Indexer.indexOf(key)]; 1113 } 1114 1115 /// Returns a pointer to the slot in the array associated with a key. 1116 pub fn getPtr(self: *Self, key: Key) *Value { 1117 return &self.values[Indexer.indexOf(key)]; 1118 } 1119 1120 /// Returns a const pointer to the slot in the array associated with a key. 1121 pub fn getPtrConst(self: *const Self, key: Key) *const Value { 1122 return &self.values[Indexer.indexOf(key)]; 1123 } 1124 1125 /// Sets the value in the slot associated with a key. 1126 pub fn set(self: *Self, key: Key, value: Value) void { 1127 self.values[Indexer.indexOf(key)] = value; 1128 } 1129 1130 /// Iterates over the items in the array, in index order. 1131 pub fn iterator(self: *Self) Iterator { 1132 return .{ 1133 .values = &self.values, 1134 }; 1135 } 1136 1137 /// An entry in the array. 1138 pub const Entry = struct { 1139 /// The key associated with this entry. 1140 /// Modifying this key will not change the array. 1141 key: Key, 1142 1143 /// A pointer to the value in the array associated 1144 /// with this key. Modifications through this 1145 /// pointer will modify the underlying data. 1146 value: *Value, 1147 }; 1148 1149 pub const Iterator = struct { 1150 index: usize = 0, 1151 values: *[Indexer.count]Value, 1152 1153 pub fn next(self: *Iterator) ?Entry { 1154 const index = self.index; 1155 if (index < Indexer.count) { 1156 self.index += 1; 1157 return Entry{ 1158 .key = Indexer.keyForIndex(index), 1159 .value = &self.values[index], 1160 }; 1161 } 1162 return null; 1163 } 1164 }; 1165 }; 1166 } 1167 1168 test "pure EnumSet fns" { 1169 const Suit = enum { spades, hearts, clubs, diamonds }; 1170 1171 const empty = EnumSet(Suit).empty; 1172 const full = EnumSet(Suit).full; 1173 const black = EnumSet(Suit).initMany(&[_]Suit{ .spades, .clubs }); 1174 const red = EnumSet(Suit).initMany(&[_]Suit{ .hearts, .diamonds }); 1175 1176 try testing.expect(empty.eql(empty)); 1177 try testing.expect(full.eql(full)); 1178 try testing.expect(!empty.eql(full)); 1179 try testing.expect(!full.eql(empty)); 1180 try testing.expect(!empty.eql(black)); 1181 try testing.expect(!full.eql(red)); 1182 try testing.expect(!red.eql(empty)); 1183 try testing.expect(!black.eql(full)); 1184 1185 try testing.expect(empty.subsetOf(empty)); 1186 try testing.expect(empty.subsetOf(full)); 1187 try testing.expect(full.subsetOf(full)); 1188 try testing.expect(!black.subsetOf(red)); 1189 try testing.expect(!red.subsetOf(black)); 1190 1191 try testing.expect(full.supersetOf(full)); 1192 try testing.expect(full.supersetOf(empty)); 1193 try testing.expect(empty.supersetOf(empty)); 1194 try testing.expect(!black.supersetOf(red)); 1195 try testing.expect(!red.supersetOf(black)); 1196 1197 try testing.expect(empty.complement().eql(full)); 1198 try testing.expect(full.complement().eql(empty)); 1199 try testing.expect(black.complement().eql(red)); 1200 try testing.expect(red.complement().eql(black)); 1201 1202 try testing.expect(empty.unionWith(empty).eql(empty)); 1203 try testing.expect(empty.unionWith(full).eql(full)); 1204 try testing.expect(full.unionWith(full).eql(full)); 1205 try testing.expect(full.unionWith(empty).eql(full)); 1206 try testing.expect(black.unionWith(red).eql(full)); 1207 try testing.expect(red.unionWith(black).eql(full)); 1208 1209 try testing.expect(empty.intersectWith(empty).eql(empty)); 1210 try testing.expect(empty.intersectWith(full).eql(empty)); 1211 try testing.expect(full.intersectWith(full).eql(full)); 1212 try testing.expect(full.intersectWith(empty).eql(empty)); 1213 try testing.expect(black.intersectWith(red).eql(empty)); 1214 try testing.expect(red.intersectWith(black).eql(empty)); 1215 1216 try testing.expect(empty.xorWith(empty).eql(empty)); 1217 try testing.expect(empty.xorWith(full).eql(full)); 1218 try testing.expect(full.xorWith(full).eql(empty)); 1219 try testing.expect(full.xorWith(empty).eql(full)); 1220 try testing.expect(black.xorWith(red).eql(full)); 1221 try testing.expect(red.xorWith(black).eql(full)); 1222 1223 try testing.expect(empty.differenceWith(empty).eql(empty)); 1224 try testing.expect(empty.differenceWith(full).eql(empty)); 1225 try testing.expect(full.differenceWith(full).eql(empty)); 1226 try testing.expect(full.differenceWith(empty).eql(full)); 1227 try testing.expect(full.differenceWith(red).eql(black)); 1228 try testing.expect(full.differenceWith(black).eql(red)); 1229 } 1230 1231 test "EnumSet empty" { 1232 const E = enum {}; 1233 const empty = EnumSet(E).empty; 1234 const full = EnumSet(E).full; 1235 1236 try std.testing.expect(empty.eql(full)); 1237 try std.testing.expect(empty.complement().eql(full)); 1238 try std.testing.expect(empty.complement().eql(full.complement())); 1239 try std.testing.expect(empty.eql(full.complement())); 1240 } 1241 1242 test "EnumSet const iterator" { 1243 const Direction = enum { up, down, left, right }; 1244 const diag_move = init: { 1245 var move = EnumSet(Direction).empty; 1246 move.insert(.right); 1247 move.insert(.up); 1248 break :init move; 1249 }; 1250 1251 var result = EnumSet(Direction).empty; 1252 var it = diag_move.iterator(); 1253 while (it.next()) |dir| { 1254 result.insert(dir); 1255 } 1256 1257 try testing.expect(result.eql(diag_move)); 1258 } 1259 1260 test "EnumSet non-exhaustive" { 1261 const BitIndices = enum(u4) { 1262 a = 0, 1263 b = 1, 1264 c = 4, 1265 _, 1266 }; 1267 const BitField = EnumSet(BitIndices); 1268 1269 var flags = BitField.init(.{ .a = true, .b = true }); 1270 flags.insert(.c); 1271 flags.remove(.a); 1272 try testing.expect(!flags.contains(.a)); 1273 try testing.expect(flags.contains(.b)); 1274 try testing.expect(flags.contains(.c)); 1275 } 1276 1277 pub fn EnumIndexer(comptime E: type) type { 1278 // n log n for `std.mem.sortUnstable` call below. 1279 const fields_len = @typeInfo(E).@"enum".field_names.len; 1280 @setEvalBranchQuota(3 * fields_len * std.math.log2(@max(fields_len, 1)) + eval_branch_quota_cushion); 1281 1282 if (@typeInfo(E).@"enum".mode == .nonexhaustive) { 1283 const BackingInt = @typeInfo(E).@"enum".tag_type; 1284 if (@bitSizeOf(BackingInt) > @bitSizeOf(usize)) 1285 @compileError("Cannot create an enum indexer for a given non-exhaustive enum, tag_type is larger than usize."); 1286 1287 return struct { 1288 pub const Key: type = E; 1289 1290 const backing_int_sign = @typeInfo(BackingInt).int.signedness; 1291 const min_value = std.math.minInt(BackingInt); 1292 const max_value = std.math.maxInt(BackingInt); 1293 1294 const RangeType = @Int(.unsigned, @bitSizeOf(BackingInt)); 1295 pub const count: comptime_int = std.math.maxInt(RangeType) + 1; 1296 1297 pub fn indexOf(e: E) usize { 1298 if (backing_int_sign == .unsigned) 1299 return @backingInt(e); 1300 1301 return if (@backingInt(e) < 0) 1302 @intCast(@backingInt(e) - min_value) 1303 else 1304 @as(RangeType, -min_value) + @as(RangeType, @intCast(@backingInt(e))); 1305 } 1306 pub fn keyForIndex(i: usize) E { 1307 if (backing_int_sign == .unsigned) 1308 return @fromBackingInt(@intCast(i)); 1309 1310 return @fromBackingInt(@intCast(@as(@Int(.signed, @bitSizeOf(RangeType) + 1), @intCast(i)) + min_value)); 1311 } 1312 }; 1313 } 1314 1315 if (fields_len == 0) { 1316 return struct { 1317 pub const Key = E; 1318 pub const count: comptime_int = 0; 1319 pub fn indexOf(e: E) usize { 1320 _ = e; 1321 unreachable; 1322 } 1323 pub fn keyForIndex(i: usize) E { 1324 _ = i; 1325 unreachable; 1326 } 1327 }; 1328 } 1329 1330 var field_values = @typeInfo(E).@"enum".field_values[0..fields_len].*; 1331 1332 std.mem.sortUnstable(comptime_int, &field_values, {}, struct { 1333 fn lessThan(_: void, a: comptime_int, b: comptime_int) bool { 1334 return a < b; 1335 } 1336 }.lessThan); 1337 1338 const min = field_values[0]; 1339 const max = field_values[fields_len - 1]; 1340 if (max - min == field_values.len - 1) { 1341 return struct { 1342 pub const Key = E; 1343 pub const count: comptime_int = fields_len; 1344 pub fn indexOf(e: E) usize { 1345 return @as(usize, @intCast(@backingInt(e) - min)); 1346 } 1347 pub fn keyForIndex(i: usize) E { 1348 // TODO fix addition semantics. This calculation 1349 // gives up some safety to avoid artificially limiting 1350 // the range of signed enum values to max_isize. 1351 const enum_value = if (min < 0) @as(isize, @bitCast(i)) +% min else i + min; 1352 return @as(E, @fromBackingInt(@intCast(@as(@typeInfo(E).@"enum".tag_type, @intCast(enum_value))))); 1353 } 1354 }; 1355 } 1356 1357 const keys = valuesFromFields(E, &field_values); 1358 1359 return struct { 1360 pub const Key = E; 1361 pub const count: comptime_int = fields_len; 1362 pub fn indexOf(e: E) usize { 1363 for (keys, 0..) |k, i| { 1364 if (k == e) return i; 1365 } 1366 unreachable; 1367 } 1368 pub fn keyForIndex(i: usize) E { 1369 return keys[i]; 1370 } 1371 }; 1372 } 1373 1374 test "EnumIndexer non-exhaustive" { 1375 const backing_ints = [_]type{ 1376 i1, 1377 i2, 1378 i3, 1379 i4, 1380 i8, 1381 i16, 1382 @Int(.signed, @bitSizeOf(isize) - 1), 1383 isize, 1384 u1, 1385 u2, 1386 u3, 1387 u4, 1388 u16, 1389 @Int(.unsigned, @bitSizeOf(usize) - 1), 1390 usize, 1391 }; 1392 inline for (backing_ints) |BackingInt| { 1393 const E = enum(BackingInt) { 1394 number_zero_tag = 0, 1395 _, 1396 }; 1397 const Indexer = EnumIndexer(E); 1398 1399 const min_tag: E = @fromBackingInt(@intCast(std.math.minInt(BackingInt))); 1400 const max_tag: E = @fromBackingInt(@intCast(std.math.maxInt(BackingInt))); 1401 1402 const RangedType = @Int(.unsigned, @bitSizeOf(BackingInt)); 1403 const max_index: comptime_int = std.math.maxInt(RangedType); 1404 const number_zero_tag_index: usize = switch (@typeInfo(BackingInt).int.signedness) { 1405 .unsigned => 0, 1406 .signed => @divCeil(max_index, 2), 1407 }; 1408 1409 try testing.expectEqual(E, Indexer.Key); 1410 try testing.expectEqual(max_index + 1, Indexer.count); 1411 1412 try testing.expectEqual(@as(usize, 0), Indexer.indexOf(min_tag)); 1413 try testing.expectEqual(number_zero_tag_index, Indexer.indexOf(E.number_zero_tag)); 1414 try testing.expectEqual(@as(usize, max_index), Indexer.indexOf(max_tag)); 1415 1416 try testing.expectEqual(min_tag, Indexer.keyForIndex(0)); 1417 try testing.expectEqual(E.number_zero_tag, Indexer.keyForIndex(number_zero_tag_index)); 1418 try testing.expectEqual(max_tag, Indexer.keyForIndex(max_index)); 1419 } 1420 } 1421 1422 test "EnumIndexer dense zeroed" { 1423 const E = enum(u2) { b = 1, a = 0, c = 2 }; 1424 const Indexer = EnumIndexer(E); 1425 try testing.expectEqual(E, Indexer.Key); 1426 try testing.expectEqual(3, Indexer.count); 1427 1428 try testing.expectEqual(@as(usize, 0), Indexer.indexOf(.a)); 1429 try testing.expectEqual(@as(usize, 1), Indexer.indexOf(.b)); 1430 try testing.expectEqual(@as(usize, 2), Indexer.indexOf(.c)); 1431 1432 try testing.expectEqual(E.a, Indexer.keyForIndex(0)); 1433 try testing.expectEqual(E.b, Indexer.keyForIndex(1)); 1434 try testing.expectEqual(E.c, Indexer.keyForIndex(2)); 1435 } 1436 1437 test "EnumIndexer dense positive" { 1438 const E = enum(u4) { c = 6, a = 4, b = 5 }; 1439 const Indexer = EnumIndexer(E); 1440 try testing.expectEqual(E, Indexer.Key); 1441 try testing.expectEqual(3, Indexer.count); 1442 1443 try testing.expectEqual(@as(usize, 0), Indexer.indexOf(.a)); 1444 try testing.expectEqual(@as(usize, 1), Indexer.indexOf(.b)); 1445 try testing.expectEqual(@as(usize, 2), Indexer.indexOf(.c)); 1446 1447 try testing.expectEqual(E.a, Indexer.keyForIndex(0)); 1448 try testing.expectEqual(E.b, Indexer.keyForIndex(1)); 1449 try testing.expectEqual(E.c, Indexer.keyForIndex(2)); 1450 } 1451 1452 test "EnumIndexer dense negative" { 1453 const E = enum(i4) { a = -6, c = -4, b = -5 }; 1454 const Indexer = EnumIndexer(E); 1455 try testing.expectEqual(E, Indexer.Key); 1456 try testing.expectEqual(3, Indexer.count); 1457 1458 try testing.expectEqual(@as(usize, 0), Indexer.indexOf(.a)); 1459 try testing.expectEqual(@as(usize, 1), Indexer.indexOf(.b)); 1460 try testing.expectEqual(@as(usize, 2), Indexer.indexOf(.c)); 1461 1462 try testing.expectEqual(E.a, Indexer.keyForIndex(0)); 1463 try testing.expectEqual(E.b, Indexer.keyForIndex(1)); 1464 try testing.expectEqual(E.c, Indexer.keyForIndex(2)); 1465 } 1466 1467 test "EnumIndexer sparse" { 1468 const E = enum(i4) { a = -2, c = 6, b = 4 }; 1469 const Indexer = EnumIndexer(E); 1470 try testing.expectEqual(E, Indexer.Key); 1471 try testing.expectEqual(3, Indexer.count); 1472 1473 try testing.expectEqual(@as(usize, 0), Indexer.indexOf(.a)); 1474 try testing.expectEqual(@as(usize, 1), Indexer.indexOf(.b)); 1475 try testing.expectEqual(@as(usize, 2), Indexer.indexOf(.c)); 1476 1477 try testing.expectEqual(E.a, Indexer.keyForIndex(0)); 1478 try testing.expectEqual(E.b, Indexer.keyForIndex(1)); 1479 try testing.expectEqual(E.c, Indexer.keyForIndex(2)); 1480 } 1481 1482 test "EnumIndexer empty" { 1483 const E = enum {}; 1484 const Indexer = EnumIndexer(E); 1485 try testing.expectEqual(E, Indexer.Key); 1486 try testing.expectEqual(0, Indexer.count); 1487 } 1488 1489 test "EnumIndexer large dense unsorted" { 1490 @setEvalBranchQuota(500_000); // many `comptimePrint`s 1491 // Make an enum with 500 fields with values in *descending* order. 1492 const E = @Enum(u32, .exhaustive, names: { 1493 var names: [500][]const u8 = undefined; 1494 for (&names, 0..) |*name, i| name.* = std.fmt.comptimePrint("f{d}", .{i}); 1495 break :names &names; 1496 }, vals: { 1497 var vals: [500]u32 = undefined; 1498 for (&vals, 0..) |*val, i| val.* = 500 - i; 1499 break :vals &vals; 1500 }); 1501 const Indexer = EnumIndexer(E); 1502 try testing.expectEqual(E.f0, Indexer.keyForIndex(499)); 1503 try testing.expectEqual(E.f499, Indexer.keyForIndex(0)); 1504 try testing.expectEqual(499, Indexer.indexOf(.f0)); 1505 try testing.expectEqual(0, Indexer.indexOf(.f499)); 1506 } 1507 1508 test values { 1509 const E = enum { 1510 X, 1511 Y, 1512 Z, 1513 const A = 1; 1514 }; 1515 try testing.expectEqualSlices(E, &.{ .X, .Y, .Z }, values(E)); 1516 } 1517