123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440 |
- //
- // Copyright © 2022 osy. All rights reserved.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- //
- import Foundation
- import Metal
- // MARK: QEMUConstant protocol
- /// A QEMU constant is a enum that can be generated externally
- protocol QEMUConstant: Codable, RawRepresentable, CaseIterable where RawValue == String, AllCases == [Self] {
- static var allRawValues: [String] { get }
- static var allPrettyValues: [String] { get }
- var prettyValue: String { get }
- var rawValue: String { get }
-
- init?(rawValue: String)
- }
- extension QEMUConstant where Self: CaseIterable, AllCases == [Self] {
- static var allRawValues: [String] {
- allCases.map { value in value.rawValue }
- }
-
- static var allPrettyValues: [String] {
- allCases.map { value in value.prettyValue }
- }
- }
- extension QEMUConstant where Self: RawRepresentable, RawValue == String {
- init(from decoder: Decoder) throws {
- let rawValue = try String(from: decoder)
- guard let representedValue = Self.init(rawValue: rawValue) else {
- throw UTMConfigurationError.invalidConfigurationValue(rawValue)
- }
- self = representedValue
- }
-
- func encode(to encoder: Encoder) throws {
- try rawValue.encode(to: encoder)
- }
- }
- protocol QEMUDefaultConstant: QEMUConstant {
- static var `default`: Self { get }
- }
- extension Optional where Wrapped: QEMUDefaultConstant {
- var _bound: Wrapped? {
- get {
- return self
- }
- set {
- self = newValue
- }
- }
-
- var bound: Wrapped {
- get {
- return _bound ?? Wrapped.default
- }
- set {
- _bound = newValue
- }
- }
- }
- /// Type erasure for a QEMU constant useful for serialization/deserialization
- struct AnyQEMUConstant: QEMUConstant, RawRepresentable {
- static var allRawValues: [String] { [] }
-
- static var allPrettyValues: [String] { [] }
-
- static var allCases: [AnyQEMUConstant] { [] }
-
- var prettyValue: String { rawValue }
-
- let rawValue: String
-
- init<C>(_ base: C) where C : QEMUConstant {
- self.rawValue = base.rawValue
- }
-
- init?(rawValue: String) {
- self.rawValue = rawValue
- }
- }
- extension QEMUConstant {
- func asAnyQEMUConstant() -> AnyQEMUConstant {
- return AnyQEMUConstant(self)
- }
- }
- extension AnyQEMUConstant: QEMUDefaultConstant {
- static var `default`: AnyQEMUConstant {
- AnyQEMUConstant(rawValue: "default")!
- }
- }
- // MARK: Enhanced type checking for generated constants
- protocol QEMUTarget: QEMUDefaultConstant {}
- extension AnyQEMUConstant: QEMUTarget {}
- protocol QEMUCPU: QEMUDefaultConstant {}
- extension AnyQEMUConstant: QEMUCPU {}
- protocol QEMUCPUFlag: QEMUConstant {}
- extension AnyQEMUConstant: QEMUCPUFlag {}
- protocol QEMUDisplayDevice: QEMUConstant {}
- extension AnyQEMUConstant: QEMUDisplayDevice {}
- protocol QEMUNetworkDevice: QEMUConstant {}
- extension AnyQEMUConstant: QEMUNetworkDevice {}
- protocol QEMUSoundDevice: QEMUConstant {}
- extension AnyQEMUConstant: QEMUSoundDevice {}
- protocol QEMUSerialDevice: QEMUConstant {}
- extension AnyQEMUConstant: QEMUSerialDevice {}
- // MARK: Display constants
- enum QEMUScaler: String, CaseIterable, QEMUConstant {
- case linear = "Linear"
- case nearest = "Nearest"
-
- var prettyValue: String {
- switch self {
- case .linear: return NSLocalizedString("Linear", comment: "UTMQemuConstants")
- case .nearest: return NSLocalizedString("Nearest Neighbor", comment: "UTMQemuConstants")
- }
- }
-
- var metalSamplerMinMagFilter: MTLSamplerMinMagFilter {
- switch self {
- case .linear: return .linear
- case .nearest: return .nearest
- }
- }
- }
- // MARK: USB constants
- enum QEMUUSBBus: String, CaseIterable, QEMUConstant {
- case disabled = "Disabled"
- case usb2_0 = "2.0"
- case usb3_0 = "3.0"
-
- var prettyValue: String {
- switch self {
- case .disabled: return NSLocalizedString("Disabled", comment: "UTMQemuConstants")
- case .usb2_0: return NSLocalizedString("USB 2.0", comment: "UTMQemuConstants")
- case .usb3_0: return NSLocalizedString("USB 3.0 (XHCI)", comment: "UTMQemuConstants")
- }
- }
- }
- // MARK: Network constants
- enum QEMUNetworkMode: String, CaseIterable, QEMUConstant {
- case emulated = "Emulated"
- case shared = "Shared"
- case host = "Host"
- case bridged = "Bridged"
-
- var prettyValue: String {
- switch self {
- case .emulated: return NSLocalizedString("Emulated VLAN", comment: "UTMQemuConstants")
- case .shared: return NSLocalizedString("Shared Network", comment: "UTMQemuConstants")
- case .host: return NSLocalizedString("Host Only", comment: "UTMQemuConstants")
- case .bridged: return NSLocalizedString("Bridged (Advanced)", comment: "UTMQemuConstants")
- }
- }
- }
- enum QEMUNetworkProtocol: String, CaseIterable, QEMUConstant {
- case tcp = "TCP"
- case udp = "UDP"
-
- var prettyValue: String {
- switch self {
- case .tcp: return NSLocalizedString("TCP", comment: "UTMQemuConstants")
- case .udp: return NSLocalizedString("UDP", comment: "UTMQemuConstants")
- }
- }
- }
- // MARK: Serial constants
- enum QEMUTerminalTheme: String, CaseIterable, QEMUDefaultConstant {
- case `default` = "Default"
-
- var prettyValue: String {
- switch self {
- case .`default`: return NSLocalizedString("Default", comment: "UTMQemuConstants")
- }
- }
- }
- struct QEMUTerminalFont: QEMUConstant {
- #if os(macOS)
- static var allRawValues: [String] = {
- NSFontManager.shared.availableFontNames(with: .fixedPitchFontMask) ?? []
- }()
-
- static var allPrettyValues: [String] = {
- allRawValues.map { name in
- NSFont(name: name, size: 1)?.displayName ?? name
- }
- }()
- #else
- static var allRawValues: [String] = {
- UIFont.familyNames.flatMap { family -> [String] in
- guard let font = UIFont(name: family, size: 1) else {
- return []
- }
- if font.fontDescriptor.symbolicTraits.contains(.traitMonoSpace) {
- return UIFont.fontNames(forFamilyName: family)
- } else {
- return []
- }
- }
- }()
-
- static var allPrettyValues: [String] = {
- allRawValues.map { name in
- guard let font = UIFont(name: name, size: 1) else {
- return name
- }
- let traits = font.fontDescriptor.symbolicTraits
- let description: String
- if traits.isSuperset(of: [.traitItalic, .traitBold]) {
- description = NSLocalizedString("Italic, Bold", comment: "UTMQemuConstants")
- } else if traits.contains(.traitItalic) {
- description = NSLocalizedString("Italic", comment: "UTMQemuConstants")
- } else if traits.contains(.traitBold) {
- description = NSLocalizedString("Bold", comment: "UTMQemuConstants")
- } else {
- description = NSLocalizedString("Regular", comment: "UTMQemuConstants")
- }
- return String.localizedStringWithFormat(NSLocalizedString("%@ (%@)", comment: "QEMUConstant"), font.familyName, description)
- }
- }()
- #endif
-
- static var allCases: [QEMUTerminalFont] {
- Self.allRawValues.map { Self(rawValue: $0) }
- }
-
- var prettyValue: String {
- guard let index = Self.allRawValues.firstIndex(of: rawValue) else {
- return rawValue
- }
- return Self.allPrettyValues[index]
- }
-
- let rawValue: String
- }
- enum QEMUSerialMode: String, CaseIterable, QEMUConstant {
- case builtin = "Terminal"
- case tcpClient = "TcpClient"
- case tcpServer = "TcpServer"
- #if os(macOS)
- case ptty = "Ptty"
- #endif
-
- var prettyValue: String {
- switch self {
- case .builtin: return NSLocalizedString("Built-in Terminal", comment: "UTMQemuConstants")
- case .tcpClient: return NSLocalizedString("TCP Client Connection", comment: "UTMQemuConstants")
- case .tcpServer: return NSLocalizedString("TCP Server Connection", comment: "UTMQemuConstants")
- #if os(macOS)
- case .ptty: return NSLocalizedString("Pseudo-TTY Device", comment: "UTMQemuConstants")
- #endif
- }
- }
- }
- enum QEMUSerialTarget: String, CaseIterable, QEMUConstant {
- case autoDevice = "Auto"
- case manualDevice = "Manual"
- case gdb = "GDB"
- case monitor = "Monitor"
-
- var prettyValue: String {
- switch self {
- case .autoDevice: return NSLocalizedString("Automatic Serial Device (max 4)", comment: "UTMQemuConstants")
- case .manualDevice: return NSLocalizedString("Manual Serial Device (advanced)", comment: "UTMQemuConstants")
- case .gdb: return NSLocalizedString("GDB Debug Stub", comment: "UTMQemuConstants")
- case .monitor: return NSLocalizedString("QEMU Monitor (HMP)", comment: "UTMQemuConstants")
- }
- }
- }
- // MARK: Drive constants
- enum QEMUDriveImageType: String, CaseIterable, QEMUConstant {
- case none = "None"
- case disk = "Disk"
- case cd = "CD"
- case bios = "BIOS"
- case linuxKernel = "LinuxKernel"
- case linuxInitrd = "LinuxInitrd"
- case linuxDtb = "LinuxDTB"
-
- var prettyValue: String {
- switch self {
- case .none: return NSLocalizedString("None", comment: "UTMQemuConstants")
- case .disk: return NSLocalizedString("Disk Image", comment: "UTMQemuConstants")
- case .cd: return NSLocalizedString("CD/DVD (ISO) Image", comment: "UTMQemuConstants")
- case .bios: return NSLocalizedString("BIOS", comment: "UTMQemuConstants")
- case .linuxKernel: return NSLocalizedString("Linux Kernel", comment: "UTMQemuConstants")
- case .linuxInitrd: return NSLocalizedString("Linux RAM Disk", comment: "UTMQemuConstants")
- case .linuxDtb: return NSLocalizedString("Linux Device Tree Binary", comment: "UTMQemuConstants")
- }
- }
- }
- enum QEMUDriveInterface: String, CaseIterable, QEMUConstant {
- case none = "None"
- case ide = "IDE"
- case scsi = "SCSI"
- case sd = "SD"
- case mtd = "MTD"
- case floppy = "Floppy"
- case pflash = "PFlash"
- case virtio = "VirtIO"
- case nvme = "NVMe"
- case usb = "USB"
-
- var prettyValue: String {
- switch self {
- case .none: return NSLocalizedString("None (Advanced)", comment: "UTMQemuConstants")
- case .ide: return NSLocalizedString("IDE", comment: "UTMQemuConstants")
- case .scsi: return NSLocalizedString("SCSI", comment: "UTMQemuConstants")
- case .sd: return NSLocalizedString("SD Card", comment: "UTMQemuConstants")
- case .mtd: return NSLocalizedString("MTD (NAND/NOR)", comment: "UTMQemuConstants")
- case .floppy: return NSLocalizedString("Floppy", comment: "UTMQemuConstants")
- case .pflash: return NSLocalizedString("PC System Flash", comment: "UTMQemuConstants")
- case .virtio: return NSLocalizedString("VirtIO", comment: "UTMQemuConstants")
- case .nvme: return NSLocalizedString("NVMe", comment: "UTMQemuConstants")
- case .usb: return NSLocalizedString("USB", comment: "UTMQemuConstants")
- }
- }
- }
- // MARK: Sharing constants
- enum QEMUFileShareMode: String, CaseIterable, QEMUConstant {
- case none = "None"
- case webdav = "WebDAV"
- case virtfs = "VirtFS"
-
- var prettyValue: String {
- switch self {
- case .none: return NSLocalizedString("None", comment: "UTMQemuConstants")
- case .webdav: return NSLocalizedString("SPICE WebDAV", comment: "UTMQemuConstants")
- case .virtfs: return NSLocalizedString("VirtFS", comment: "UTMQemuConstants")
- }
- }
- }
- // MARK: File names
- enum QEMUPackageFileName: String {
- case images = "Images"
- case debugLog = "debug.log"
- case efiVariables = "efi_vars.fd"
- }
- // MARK: Supported features
- extension QEMUArchitecture {
- var hasAgentSupport: Bool {
- switch self {
- case .sparc, .sparc64: return false
- default: return true
- }
- }
-
- var hasSharingSupport: Bool {
- switch self {
- case .sparc, .sparc64: return false
- default: return true
- }
- }
-
- var hasUsbSupport: Bool {
- switch self {
- case .s390x: return false
- case .sparc, .sparc64: return false
- default: return true
- }
- }
-
- var hasHypervisorSupport: Bool {
- guard jb_has_hypervisor() else {
- return false
- }
- #if arch(arm64)
- return self == .aarch64
- #elseif arch(x86_64)
- return self == .x86_64
- #else
- return false
- #endif
- }
- }
- extension QEMUTarget {
- var hasUsbSupport: Bool {
- switch self.rawValue {
- case "isapc": return false
- default: return true
- }
- }
- }
|