diff --git a/lib/std/os/uefi/protocols/device_path_protocol.zig b/lib/std/os/uefi/protocols/device_path_protocol.zig index a6509bb14f..ae5822ba35 100644 --- a/lib/std/os/uefi/protocols/device_path_protocol.zig +++ b/lib/std/os/uefi/protocols/device_path_protocol.zig @@ -72,66 +72,39 @@ pub const DevicePathProtocol = packed struct { } pub fn getDevicePath(self: *const DevicePathProtocol) ?DevicePath { - return switch (self.type) { - .Hardware => blk: { - const hardware: ?HardwareDevicePath = switch (@intToEnum(HardwareDevicePath.Subtype, self.subtype)) { - .Pci => .{ .Pci = @ptrCast(*const HardwareDevicePath.PciDevicePath, self) }, - .PcCard => .{ .PcCard = @ptrCast(*const HardwareDevicePath.PcCardDevicePath, self) }, - .MemoryMapped => .{ .MemoryMapped = @ptrCast(*const HardwareDevicePath.MemoryMappedDevicePath, self) }, - .Vendor => .{ .Vendor = @ptrCast(*const HardwareDevicePath.VendorDevicePath, self) }, - .Controller => .{ .Controller = @ptrCast(*const HardwareDevicePath.ControllerDevicePath, self) }, - .Bmc => .{ .Bmc = @ptrCast(*const HardwareDevicePath.BmcDevicePath, self) }, - _ => null, - }; - break :blk if (hardware) |h| .{ .Hardware = h } else null; - }, - .Acpi => blk: { - const acpi: ?AcpiDevicePath = switch (@intToEnum(AcpiDevicePath.Subtype, self.subtype)) { - .Acpi => .{ .Acpi = @ptrCast(*const AcpiDevicePath.BaseAcpiDevicePath, self) }, - .ExpandedAcpi => .{ .ExpandedAcpi = @ptrCast(*const AcpiDevicePath.ExpandedAcpiDevicePath, self) }, - .Adr => .{ .Adr = @ptrCast(*const AcpiDevicePath.AdrDevicePath, self) }, - _ => null, - }; - break :blk if (acpi) |a| .{ .Acpi = a } else null; - }, - .Messaging => blk: { - const messaging: ?MessagingDevicePath = switch (@intToEnum(MessagingDevicePath.Subtype, self.subtype)) { - else => null, // TODO - }; - break :blk if (messaging) |m| .{ .Messaging = m } else null; - }, - .Media => blk: { - const media: ?MediaDevicePath = switch (@intToEnum(MediaDevicePath.Subtype, self.subtype)) { - .HardDrive => .{ .HardDrive = @ptrCast(*const MediaDevicePath.HardDriveDevicePath, self) }, - .Cdrom => .{ .Cdrom = @ptrCast(*const MediaDevicePath.CdromDevicePath, self) }, - .Vendor => .{ .Vendor = @ptrCast(*const MediaDevicePath.VendorDevicePath, self) }, - .FilePath => .{ .FilePath = @ptrCast(*const MediaDevicePath.FilePathDevicePath, self) }, - .MediaProtocol => .{ .MediaProtocol = @ptrCast(*const MediaDevicePath.MediaProtocolDevicePath, self) }, - .PiwgFirmwareFile => .{ .PiwgFirmwareFile = @ptrCast(*const MediaDevicePath.PiwgFirmwareFileDevicePath, self) }, - .PiwgFirmwareVolume => .{ .PiwgFirmwareVolume = @ptrCast(*const MediaDevicePath.PiwgFirmwareVolumeDevicePath, self) }, - .RelativeOffsetRange => .{ .RelativeOffsetRange = @ptrCast(*const MediaDevicePath.RelativeOffsetRangeDevicePath, self) }, - .RamDisk => .{ .RamDisk = @ptrCast(*const MediaDevicePath.RamDiskDevicePath, self) }, - _ => null, - }; - break :blk if (media) |m| .{ .Media = m } else null; - }, - .BiosBootSpecification => blk: { - const bbs: ?BiosBootSpecificationDevicePath = switch (@intToEnum(BiosBootSpecificationDevicePath.Subtype, self.subtype)) { - .BBS101 => .{ .BBS101 = @ptrCast(*const BiosBootSpecificationDevicePath.BBS101DevicePath, self) }, - _ => null, - }; - break :blk if (bbs) |b| .{ .BiosBootSpecification = b } else null; - }, - .End => blk: { - const end: ?EndDevicePath = switch (@intToEnum(EndDevicePath.Subtype, self.subtype)) { - .EndEntire => .{ .EndEntire = @ptrCast(*const EndDevicePath.EndEntireDevicePath, self) }, - .EndThisInstance => .{ .EndThisInstance = @ptrCast(*const EndDevicePath.EndThisInstanceDevicePath, self) }, - _ => null, - }; - break :blk if (end) |e| .{ .End = e } else null; - }, - _ => null, - }; + inline for (@typeInfo(DevicePath).Union.fields) |ufield| { + const enum_value = std.meta.stringToEnum(DevicePathType, ufield.name); + + // Got the associated union type for self.type, now + // we need to initialize it and its subtype + if (self.type == enum_value) { + var subtype = self.initSubtype(ufield.field_type); + + if (subtype) |sb| { + // e.g. return .{ .Hardware = .{ .Pci = @ptrCast(...) } } + return @unionInit(DevicePath, ufield.name, sb); + } + } + } + + return null; + } + + pub fn initSubtype(self: *const DevicePathProtocol, comptime TUnion: type) ?TUnion { + const type_info = @typeInfo(TUnion).Union; + const TTag = type_info.tag_type.?; + + inline for (type_info.fields) |subtype| { + // The tag names match the union names, so just grab that off the enum + const tag_val: u8 = @enumToInt(@field(TTag, subtype.name)); + + if (self.subtype == tag_val) { + // e.g. expr = .{ .Pci = @ptrCast(...) } + return @unionInit(TUnion, subtype.name, @ptrCast(subtype.field_type, self)); + } + } + + return null; } }; @@ -268,7 +241,7 @@ pub const MessagingDevicePath = union(Subtype) { Atapi: *const AtapiDevicePath, Scsi: *const ScsiDevicePath, FibreChannel: *const FibreChannelDevicePath, - FibreChannelEx: FibreChannelExDevicePath, + FibreChannelEx: *const FibreChannelExDevicePath, @"1394": *const F1394DevicePath, Usb: *const UsbDevicePath, Sata: *const SataDevicePath,