Promote the runtime per-instrument flag from a bare reason string to an InstrumentStatus enum so later kinds (load, reload, compile failures) can share the surface. Behaviour is unchanged: skipIfIncompatible sets .incompatible and the sidebar still renders a single warning icon.
125 lines
3.8 KiB
Swift
125 lines
3.8 KiB
Swift
import Foundation
|
|
|
|
public struct InstrumentCompatibility: Codable, Hashable, Sendable {
|
|
public var platforms: Set<String>?
|
|
public var osIDs: Set<String>?
|
|
public var archs: Set<String>?
|
|
|
|
public static let universal = InstrumentCompatibility()
|
|
|
|
public init(
|
|
platforms: Set<String>? = nil,
|
|
osIDs: Set<String>? = nil,
|
|
archs: Set<String>? = nil
|
|
) {
|
|
self.platforms = platforms?.nilIfEmpty
|
|
self.osIDs = osIDs?.nilIfEmpty
|
|
self.archs = archs?.nilIfEmpty
|
|
}
|
|
|
|
public var isUniversal: Bool {
|
|
platforms == nil && osIDs == nil && archs == nil
|
|
}
|
|
|
|
public func matches(_ params: SystemParameters) -> Bool {
|
|
incompatibilityReason(for: params) == nil
|
|
}
|
|
|
|
public func incompatibilityReason(for params: SystemParameters) -> String? {
|
|
var requirements: [String] = []
|
|
if let platforms, !platforms.contains(params.platform) {
|
|
requirements.append("platform \(formatRequirement(platforms, displayedBy: InstrumentCompatibility.platformDisplayName))")
|
|
}
|
|
if let osIDs, !osIDs.contains(params.osID) {
|
|
requirements.append("OS \(formatRequirement(osIDs, displayedBy: InstrumentCompatibility.osDisplayName))")
|
|
}
|
|
if let archs, !archs.contains(params.arch) {
|
|
requirements.append("architecture \(formatRequirement(archs, displayedBy: InstrumentCompatibility.archDisplayName))")
|
|
}
|
|
guard !requirements.isEmpty else { return nil }
|
|
return "Requires \(requirements.joined(separator: ", ")); this session is \(describeSession(params))"
|
|
}
|
|
|
|
private func formatRequirement(_ values: Set<String>, displayedBy display: (String) -> String) -> String {
|
|
values.map(display).sorted().joined(separator: "/")
|
|
}
|
|
|
|
private func describeSession(_ params: SystemParameters) -> String {
|
|
"\(InstrumentCompatibility.osDisplayName(params.osID))/\(InstrumentCompatibility.archDisplayName(params.arch))"
|
|
}
|
|
|
|
public static func platformDisplayName(_ raw: String) -> String {
|
|
platformDisplayNames[raw] ?? raw
|
|
}
|
|
|
|
public static func osDisplayName(_ raw: String) -> String {
|
|
osDisplayNames[raw] ?? raw
|
|
}
|
|
|
|
public static func archDisplayName(_ raw: String) -> String {
|
|
archDisplayNames[raw] ?? raw
|
|
}
|
|
|
|
private static let platformDisplayNames: [String: String] = [
|
|
"windows": "Windows",
|
|
"darwin": "Darwin",
|
|
"linux": "Linux",
|
|
"freebsd": "FreeBSD",
|
|
"qnx": "QNX",
|
|
"barebone": "Barebone",
|
|
]
|
|
|
|
private static let osDisplayNames: [String: String] = [
|
|
"windows": "Windows",
|
|
"macos": "macOS",
|
|
"linux": "Linux",
|
|
"ios": "iOS",
|
|
"watchos": "watchOS",
|
|
"tvos": "tvOS",
|
|
"visionos": "visionOS",
|
|
"android": "Android",
|
|
"freebsd": "FreeBSD",
|
|
"qnx": "QNX",
|
|
]
|
|
|
|
private static let archDisplayNames: [String: String] = [
|
|
"ia32": "x86",
|
|
"x64": "x86_64",
|
|
"arm": "arm",
|
|
"arm64": "arm64",
|
|
"mips": "MIPS",
|
|
]
|
|
}
|
|
|
|
public struct SystemParameters: Hashable, Sendable {
|
|
public let platform: String
|
|
public let osID: String
|
|
public let arch: String
|
|
|
|
public init(platform: String, osID: String, arch: String) {
|
|
self.platform = platform
|
|
self.osID = osID
|
|
self.arch = arch
|
|
}
|
|
|
|
public init?(raw: [String: Any]) {
|
|
guard
|
|
let platform = raw["platform"] as? String,
|
|
let arch = raw["arch"] as? String,
|
|
let os = raw["os"] as? [String: Any],
|
|
let osID = os["id"] as? String
|
|
else {
|
|
return nil
|
|
}
|
|
self.platform = platform
|
|
self.osID = osID
|
|
self.arch = arch
|
|
}
|
|
}
|
|
|
|
extension Set {
|
|
fileprivate var nilIfEmpty: Self? {
|
|
isEmpty ? nil : self
|
|
}
|
|
}
|