diff --git a/Package.swift b/Package.swift index c7621c05..a75a0bd9 100644 --- a/Package.swift +++ b/Package.swift @@ -31,17 +31,23 @@ struct Available { var swiftSetting: SwiftSetting { #if SYSTEM_ABI_STABLE // Use availability matching Darwin API. - let availability = self.osAvailability + let availabilityType = self.osAvailability #else // Use availability matching SwiftPM default. - let availability = self.sourceAvailability + let availabilityType = self.sourceAvailability #endif return .enableExperimentalFeature( - "AvailabilityMacro=\(self.name) \(version):\(availability)") + "AvailabilityMacro=\(self.name) \(version):\(availabilityType)") + } + + var compatibilitySetting: SwiftSetting { + .enableExperimentalFeature( + "AvailabilityMacro=\(self.name) \(version):\(osAvailability)" + ) } } -let availability: [Available] = [ +let availabilityList: [Available] = [ Available("0.0.1", "macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0"), Available("0.0.2", "macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0"), @@ -68,7 +74,7 @@ let availability: [Available] = [ Available("99", "macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, visionOS 9999"), ] -let swiftSettingsAvailability = availability.map(\.swiftSetting) +let availabilitySettings = availabilityList.map(\.swiftSetting) #if SYSTEM_CI let swiftSettingsCI: [SwiftSetting] = [ @@ -78,7 +84,7 @@ let swiftSettingsCI: [SwiftSetting] = [ let swiftSettingsCI: [SwiftSetting] = [] #endif -let swiftSettings = swiftSettingsAvailability + swiftSettingsCI + [ +let sharedSwiftSettings = swiftSettingsCI + [ .define( "SYSTEM_PACKAGE_DARWIN", .when(platforms: [.macOS, .macCatalyst, .iOS, .watchOS, .tvOS, .visionOS])), @@ -87,6 +93,8 @@ let swiftSettings = swiftSettingsAvailability + swiftSettingsCI + [ .enableExperimentalFeature("Lifetimes"), ] +let swiftSettings = sharedSwiftSettings + availabilitySettings + let cSettings: [CSetting] = [ .define("_CRT_SECURE_NO_WARNINGS", .when(platforms: [.windows])), ] @@ -135,12 +143,29 @@ let package = Package( exclude: filesToExclude, cSettings: cSettings, swiftSettings: swiftSettings), + .target( + name: "SystemCompatibilityAdaptors", + dependencies: ["SystemPackage"], + path: "Sources/SystemCompatibilityAdaptors", + exclude: [], + cSettings: cSettings, + swiftSettings: + sharedSwiftSettings + availabilityList.map(\.compatibilitySetting) + ), .testTarget( name: "SystemTests", dependencies: ["SystemPackage"], exclude: testsToExclude, cSettings: cSettings, swiftSettings: swiftSettings), + .testTarget( + name: "SystemCompatibilityAdaptorTests", + dependencies: ["SystemCompatibilityAdaptors", "SystemPackage"], + exclude: [], + cSettings: cSettings, + swiftSettings: + sharedSwiftSettings + availabilityList.map(\.compatibilitySetting) + ), ], swiftLanguageVersions: [.v5] ) diff --git a/Sources/SystemCompatibilityAdaptors/CompatibilityAdaptors.swift b/Sources/SystemCompatibilityAdaptors/CompatibilityAdaptors.swift new file mode 100644 index 00000000..95845ec7 --- /dev/null +++ b/Sources/SystemCompatibilityAdaptors/CompatibilityAdaptors.swift @@ -0,0 +1,43 @@ +/* + This source file is part of the Swift System open source project + + Copyright (c) 2025 - 2026 Apple Inc. and the Swift System project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information +*/ + +#if canImport(System) && canImport(SystemPackage) +import System +import SystemPackage + +extension SystemPackage.FilePath { + @available(System 0.0.2, *) + public init(converting path: System.FilePath) { + self = path.withPlatformString(Self.init(platformString:)) + } +} + +@available(System 0.0.1, *) +extension System.FilePath { + @available(System 0.0.2, *) + public init(converting path: SystemPackage.FilePath) { + self = path.withPlatformString(Self.init(platformString:)) + } +} + +extension SystemPackage.FileDescriptor { + @available(System 0.0.1, *) + public init(converting descriptor: System.FileDescriptor) { + self.init(rawValue: descriptor.rawValue) + } +} + +@available(System 0.0.1, *) +extension System.FileDescriptor { + @available(System 0.0.1, *) + public init(converting descriptor: SystemPackage.FileDescriptor) { + self.init(rawValue: descriptor.rawValue) + } +} +#endif // canImport(System) && canImport(SystemPackage) diff --git a/Tests/SystemCompatibilityAdaptorTests/AdaptorTests.swift b/Tests/SystemCompatibilityAdaptorTests/AdaptorTests.swift new file mode 100644 index 00000000..a6c3cbbb --- /dev/null +++ b/Tests/SystemCompatibilityAdaptorTests/AdaptorTests.swift @@ -0,0 +1,34 @@ +#if canImport(System) && canImport(SystemPackage) + +import Testing + +import SystemPackage +import System + +import SystemCompatibilityAdaptors + +@Suite("CompatibilityAdaptors") +private struct CompatibilityAdaptorTests { + + @available(System 0.0.2, *) + @Test + func filePathAdaptor() throws { + let fp = SystemPackage.FilePath("/bar") + + let sfp = System.FilePath(converting: fp) + + // If we had access to the underlying array as API, this would look less silly + #expect(fp == SystemPackage.FilePath(converting: sfp)) + } + + @available(System 0.0.1, *) + @Test + func fileDescriptorAdaptor() throws { + let fd = try SystemPackage.FileDescriptor.standardInput.duplicate() + + let sfd: System.FileDescriptor = System.FileDescriptor(converting: fd) + + #expect(fd.rawValue == sfd.rawValue) + } +} +#endif // canImport(System) && canImport(SystemPackage)