From 8bca78ddd2f318be023a286099e5e4174892a05d Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Wed, 3 Dec 2025 17:30:22 -0800 Subject: [PATCH 1/3] A sketch for an adaptors module --- Package.swift | 15 ++++++++ .../CompatibilityAdaptors.swift | 36 +++++++++++++++++++ .../AdaptorTests.swift | 30 ++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 Sources/SystemCompatibilityAdaptors/CompatibilityAdaptors.swift create mode 100644 Tests/SystemCompatibilityAdaptorTests/AdaptorTests.swift diff --git a/Package.swift b/Package.swift index c7621c05..1dda749e 100644 --- a/Package.swift +++ b/Package.swift @@ -135,12 +135,27 @@ let package = Package( exclude: filesToExclude, cSettings: cSettings, swiftSettings: swiftSettings), + .target( + name: "SystemCompatibilityAdaptors", + dependencies: ["SystemPackage"], + path: "Sources/SystemCompatibilityAdaptors", + exclude: [], + cSettings: cSettings, + swiftSettings: swiftSettings + ), .testTarget( name: "SystemTests", dependencies: ["SystemPackage"], exclude: testsToExclude, cSettings: cSettings, swiftSettings: swiftSettings), + .testTarget( + name: "SystemCompatibilityAdaptorTests", + dependencies: ["SystemCompatibilityAdaptors", "SystemPackage"], + exclude: [], + cSettings: cSettings, + swiftSettings: swiftSettings + ), ], swiftLanguageVersions: [.v5] ) diff --git a/Sources/SystemCompatibilityAdaptors/CompatibilityAdaptors.swift b/Sources/SystemCompatibilityAdaptors/CompatibilityAdaptors.swift new file mode 100644 index 00000000..ae036b68 --- /dev/null +++ b/Sources/SystemCompatibilityAdaptors/CompatibilityAdaptors.swift @@ -0,0 +1,36 @@ +#if canImport(System) && canImport(SystemPackage) +import System +import SystemPackage + +@available(System 0.0.2, *) +extension SystemPackage.FilePath { + @available(System 0.0.2, *) + public init(converting path: System.FilePath) { + self = path.withPlatformString(Self.init(platformString:)) + } +} + +@available(System 0.0.2, *) +extension System.FilePath { + @available(System 0.0.2, *) + public init(converting path: SystemPackage.FilePath) { + self = path.withPlatformString(Self.init(platformString:)) + } +} + +@available(System 0.0.1, *) +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..69d57404 --- /dev/null +++ b/Tests/SystemCompatibilityAdaptorTests/AdaptorTests.swift @@ -0,0 +1,30 @@ +#if canImport(System) && canImport(SystemPackage) + +import XCTest + +import SystemPackage +import System + +import SystemCompatibilityAdaptors + +final class SystemCompatibilityAdaptorTests: XCTestCase { + + func testFilePathAdaptor() { + 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 + XCTAssertEqual(fp, SystemPackage.FilePath(converting: sfp)) + } + + func testFileDescriptorAdaptor() throws { + let fd = try SystemPackage.FileDescriptor.standardInput.duplicate() + + let sfd: System.FileDescriptor = System.FileDescriptor(converting: fd) + + print(fd.rawValue) + XCTAssertEqual(fd.rawValue, sfd.rawValue) + } +} +#endif // canImport(System) && canImport(SystemPackage) From 305d7885fc52f12517a5f17ebcd7aea234328a4c Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Tue, 6 Jan 2026 16:44:49 -0800 Subject: [PATCH 2/3] fix availability macro invocation --- Package.swift | 26 +++++++++++++------ .../CompatibilityAdaptors.swift | 13 +++++++--- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/Package.swift b/Package.swift index 1dda749e..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])), ] @@ -141,7 +149,8 @@ let package = Package( path: "Sources/SystemCompatibilityAdaptors", exclude: [], cSettings: cSettings, - swiftSettings: swiftSettings + swiftSettings: + sharedSwiftSettings + availabilityList.map(\.compatibilitySetting) ), .testTarget( name: "SystemTests", @@ -154,7 +163,8 @@ let package = Package( dependencies: ["SystemCompatibilityAdaptors", "SystemPackage"], exclude: [], cSettings: cSettings, - swiftSettings: swiftSettings + swiftSettings: + sharedSwiftSettings + availabilityList.map(\.compatibilitySetting) ), ], swiftLanguageVersions: [.v5] diff --git a/Sources/SystemCompatibilityAdaptors/CompatibilityAdaptors.swift b/Sources/SystemCompatibilityAdaptors/CompatibilityAdaptors.swift index ae036b68..95845ec7 100644 --- a/Sources/SystemCompatibilityAdaptors/CompatibilityAdaptors.swift +++ b/Sources/SystemCompatibilityAdaptors/CompatibilityAdaptors.swift @@ -1,8 +1,16 @@ +/* + 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 -@available(System 0.0.2, *) extension SystemPackage.FilePath { @available(System 0.0.2, *) public init(converting path: System.FilePath) { @@ -10,7 +18,7 @@ extension SystemPackage.FilePath { } } -@available(System 0.0.2, *) +@available(System 0.0.1, *) extension System.FilePath { @available(System 0.0.2, *) public init(converting path: SystemPackage.FilePath) { @@ -18,7 +26,6 @@ extension System.FilePath { } } -@available(System 0.0.1, *) extension SystemPackage.FileDescriptor { @available(System 0.0.1, *) public init(converting descriptor: System.FileDescriptor) { From 13822870366d7d35f4987c6bc54817c90f22b347 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Tue, 6 Jan 2026 16:49:36 -0800 Subject: [PATCH 3/3] Use swift-testing to test compatibility adaptors --- .../AdaptorTests.swift | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/Tests/SystemCompatibilityAdaptorTests/AdaptorTests.swift b/Tests/SystemCompatibilityAdaptorTests/AdaptorTests.swift index 69d57404..a6c3cbbb 100644 --- a/Tests/SystemCompatibilityAdaptorTests/AdaptorTests.swift +++ b/Tests/SystemCompatibilityAdaptorTests/AdaptorTests.swift @@ -1,30 +1,34 @@ #if canImport(System) && canImport(SystemPackage) -import XCTest +import Testing import SystemPackage import System import SystemCompatibilityAdaptors -final class SystemCompatibilityAdaptorTests: XCTestCase { +@Suite("CompatibilityAdaptors") +private struct CompatibilityAdaptorTests { - func testFilePathAdaptor() { + @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 - XCTAssertEqual(fp, SystemPackage.FilePath(converting: sfp)) + #expect(fp == SystemPackage.FilePath(converting: sfp)) } - func testFileDescriptorAdaptor() throws { + @available(System 0.0.1, *) + @Test + func fileDescriptorAdaptor() throws { let fd = try SystemPackage.FileDescriptor.standardInput.duplicate() let sfd: System.FileDescriptor = System.FileDescriptor(converting: fd) - print(fd.rawValue) - XCTAssertEqual(fd.rawValue, sfd.rawValue) + #expect(fd.rawValue == sfd.rawValue) } } #endif // canImport(System) && canImport(SystemPackage)