pub const fmt = @import("fmt.zig"); pub const pretty = fmt.pretty; pub fn CombinedEnum(comptime parent: type) type { const parent_info = @typeInfo(parent).@"struct"; var num_fields = 0; var num_enums = 0; for (parent_info.decls) |partial| { switch (@typeInfo(@field(parent, partial.name))) { .@"enum" => |e| { num_fields += e.fields.len; num_enums += 1; }, else => {}, } } const ConversionMap = struct { start: comptime_int = 0, end: comptime_int = 0, T: type, }; var combined: [num_fields][:0]const u8 = undefined; var combined_values: [num_fields]u8 = undefined; var conv_map: [num_enums]ConversionMap = undefined; var idx = 0; var i = 0; for (parent_info.decls) |partial| { switch (@typeInfo(@field(parent, partial.name))) { .@"enum" => |e| { conv_map[idx] = .{ .start = i, .end = i + e.fields.len - 1, .T = @field(parent, partial.name), }; for (e.fields) |field| { combined[i] = field.name; combined_values[i] = field.value; i += 1; } idx += 1; }, else => {}, } } // const combined_enum = @Enum(std.builtin.Type{ .@"enum" = .{ // .decls = &.{}, // .fields = &combined, // .tag_type = u8, // .is_exhaustive = true, // } }); const combined_enum = @Enum( u8, .nonexhaustive, &combined, &combined_values, ); const combined_enums = num_enums; const conv_map_const = conv_map; return struct { pub const Combined = combined_enum; const conversion_map: [combined_enums]ConversionMap = conv_map_const; pub fn originalType(value: @TypeOf(Combined)) type { const int_rep: u8 = @intFromEnum(value); for (conversion_map) |map| { if (map.start <= int_rep and int_rep <= map.end) return map.T; } } }; } test { const testing = @import("std").testing; testing.refAllDeclsRecursive(@This()); }