Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable strict concurrency #14

Merged
merged 4 commits into from
Jul 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,5 @@ jobs:
uses: StanfordBDHG/.github/.github/workflows/create-and-upload-coverage-report.yml@v2
with:
coveragereports: XCTRuntimeAssertions-iOS.xcresult XCTRuntimeAssertions-watchOS.xcresult XCTRuntimeAssertions-visionOS.xcresult XCTRuntimeAssertions-tvOS.xcresult XCTRuntimeAssertions-macOS.xcresult
secrets:
token: ${{ secrets.CODECOV_TOKEN }}
4 changes: 0 additions & 4 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,6 @@ only_rules:
- implicitly_unwrapped_optional
# Identifiers should use inclusive language that avoids discrimination against groups of people based on race, gender, or socioeconomic status
- inclusive_language
# If defer is at the end of its parent scope, it will be executed right where it is anyway.
- inert_defer
# Prefer using Set.isDisjoint(with:) over Set.intersection(_:).isEmpty.
- is_disjoint
# Discouraged explicit usage of the default separator.
Expand Down Expand Up @@ -329,8 +327,6 @@ only_rules:
- unowned_variable_capture
# Catch statements should not declare error variables without type casting.
- untyped_error_in_catch
# Unused reference in a capture list should be removed.
- unused_capture_list
# Unused parameter in a closure should be replaced with _.
- unused_closure_parameter
# Unused control flow label should be removed.
Expand Down
37 changes: 35 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,15 @@
// SPDX-License-Identifier: MIT
//

import class Foundation.ProcessInfo
import PackageDescription

#if swift(<6)
let swiftConcurrency: SwiftSetting = .enableExperimentalFeature("StrictConcurrency")
#else
let swiftConcurrency: SwiftSetting = .enableUpcomingFeature("StrictConcurrency")
#endif


let package = Package(
name: "XCTRuntimeAssertions",
Expand All @@ -23,15 +30,41 @@ let package = Package(
products: [
.library(name: "XCTRuntimeAssertions", targets: ["XCTRuntimeAssertions"])
],
dependencies: swiftLintPackage(),
targets: [
.target(
name: "XCTRuntimeAssertions"
name: "XCTRuntimeAssertions",
swiftSettings: [
swiftConcurrency
],
plugins: [] + swiftLintPlugin()
),
.testTarget(
name: "XCTRuntimeAssertionsTests",
dependencies: [
.target(name: "XCTRuntimeAssertions")
]
],
swiftSettings: [
swiftConcurrency
],
plugins: [] + swiftLintPlugin()
)
]
)

func swiftLintPlugin() -> [Target.PluginUsage] {
// Fully quit Xcode and open again with `open --env SPEZI_DEVELOPMENT_SWIFTLINT /Applications/Xcode.app`
if ProcessInfo.processInfo.environment["SPEZI_DEVELOPMENT_SWIFTLINT"] != nil {
[.plugin(name: "SwiftLintBuildToolPlugin", package: "SwiftLint")]
} else {
[]
}
}

func swiftLintPackage() -> [PackageDescription.Package.Dependency] {
if ProcessInfo.processInfo.environment["SPEZI_DEVELOPMENT_SWIFTLINT"] != nil {
[.package(url: "https://github.com/realm/SwiftLint.git", .upToNextMinor(from: "0.55.1"))]
} else {
[]
}
}
52 changes: 42 additions & 10 deletions Sources/XCTRuntimeAssertions/XCTRuntimeAssertionInjector.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,39 @@
import Foundation


private final class RuntimeInjections: Sendable {
private nonisolated(unsafe) var injected: [XCTRuntimeAssertionInjector] = []

Check warning on line 14 in Sources/XCTRuntimeAssertions/XCTRuntimeAssertionInjector.swift

View workflow job for this annotation

GitHub Actions / Build and Test Swift Package visionOS / Test using xcodebuild or run fastlane

stored property 'injected' of 'Sendable'-conforming class 'RuntimeInjections' is mutable

Check warning on line 14 in Sources/XCTRuntimeAssertions/XCTRuntimeAssertionInjector.swift

View workflow job for this annotation

GitHub Actions / Build and Test Swift Package visionOS / Test using xcodebuild or run fastlane

stored property 'injected' of 'Sendable'-conforming class 'RuntimeInjections' is mutable

Check warning on line 14 in Sources/XCTRuntimeAssertions/XCTRuntimeAssertionInjector.swift

View workflow job for this annotation

GitHub Actions / Build and Test Swift Package macOS / Test using xcodebuild or run fastlane

stored property 'injected' of 'Sendable'-conforming class 'RuntimeInjections' is mutable

Check warning on line 14 in Sources/XCTRuntimeAssertions/XCTRuntimeAssertionInjector.swift

View workflow job for this annotation

GitHub Actions / Build and Test Swift Package macOS / Test using xcodebuild or run fastlane

stored property 'injected' of 'Sendable'-conforming class 'RuntimeInjections' is mutable

Check warning on line 14 in Sources/XCTRuntimeAssertions/XCTRuntimeAssertionInjector.swift

View workflow job for this annotation

GitHub Actions / Build and Test Swift Package iOS / Test using xcodebuild or run fastlane

stored property 'injected' of 'Sendable'-conforming class 'RuntimeInjections' is mutable

Check warning on line 14 in Sources/XCTRuntimeAssertions/XCTRuntimeAssertionInjector.swift

View workflow job for this annotation

GitHub Actions / Build and Test Swift Package iOS / Test using xcodebuild or run fastlane

stored property 'injected' of 'Sendable'-conforming class 'RuntimeInjections' is mutable

Check warning on line 14 in Sources/XCTRuntimeAssertions/XCTRuntimeAssertionInjector.swift

View workflow job for this annotation

GitHub Actions / Build and Test Swift Package tvOS / Test using xcodebuild or run fastlane

stored property 'injected' of 'Sendable'-conforming class 'RuntimeInjections' is mutable

Check warning on line 14 in Sources/XCTRuntimeAssertions/XCTRuntimeAssertionInjector.swift

View workflow job for this annotation

GitHub Actions / Build and Test Swift Package tvOS / Test using xcodebuild or run fastlane

stored property 'injected' of 'Sendable'-conforming class 'RuntimeInjections' is mutable

Check warning on line 14 in Sources/XCTRuntimeAssertions/XCTRuntimeAssertionInjector.swift

View workflow job for this annotation

GitHub Actions / Build and Test Swift Package watchOS / Test using xcodebuild or run fastlane

stored property 'injected' of 'Sendable'-conforming class 'RuntimeInjections' is mutable

Check warning on line 14 in Sources/XCTRuntimeAssertions/XCTRuntimeAssertionInjector.swift

View workflow job for this annotation

GitHub Actions / Build and Test Swift Package watchOS / Test using xcodebuild or run fastlane

stored property 'injected' of 'Sendable'-conforming class 'RuntimeInjections' is mutable
private let lock = NSLock()

@inlinable var isEmpty: Bool {
injected.isEmpty
}

var injections: [XCTRuntimeAssertionInjector] {
lock.withLock {
injected
}
}

init() {}

func append(_ element: XCTRuntimeAssertionInjector) {
lock.withLock {
injected.append(element)
}
}

func removeAll(for id: UUID) {
lock.withLock {
injected.removeAll(where: { $0.id == id })
}
}
}


class XCTRuntimeAssertionInjector {
private static var injected: [XCTRuntimeAssertionInjector] = []
private static let injection = RuntimeInjections()


let id: UUID
private let _assert: (UUID, () -> Bool, () -> String, StaticString, UInt) -> Void
Expand Down Expand Up @@ -65,30 +95,32 @@


static func inject(runtimeAssertionInjector: XCTRuntimeAssertionInjector) {
injected.append(runtimeAssertionInjector)
injection.append(runtimeAssertionInjector)
}

static func removeRuntimeAssertionInjector(withId id: UUID) {
injected.removeAll(where: { $0.id == id })
injection.removeAll(for: id)
}



@inlinable
static func assert(_ condition: () -> Bool, message: () -> String, file: StaticString, line: UInt) {
if injected.isEmpty {
if injection.isEmpty {
Swift.assert(condition(), message(), file: file, line: line)
}

for runtimeAssertionInjector in injected {
for runtimeAssertionInjector in injection.injections {
runtimeAssertionInjector._assert(runtimeAssertionInjector.id, condition, message, file, line)
}
}


@inlinable
static func precondition(_ condition: () -> Bool, message: () -> String, file: StaticString, line: UInt) {
if injected.isEmpty {
if injection.isEmpty {
Swift.precondition(condition(), message(), file: file, line: line)
}

for runtimeAssertionInjector in injected {
for runtimeAssertionInjector in injection.injections {
runtimeAssertionInjector._precondition(runtimeAssertionInjector.id, condition, message, file, line)
}
}
Expand Down
4 changes: 2 additions & 2 deletions Sources/XCTRuntimeAssertions/XCTRuntimePrecondition.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public func XCTRuntimePrecondition(
_ message: @autoclosure () -> String = "",
file: StaticString = #filePath,
line: UInt = #line,
_ expression: @escaping () -> Void
_ expression: @escaping @Sendable () -> Void
) throws {
let fulfillmentCount = Counter()
let xctRuntimeAssertionId = setupXCTRuntimeAssertionInjector(
Expand Down Expand Up @@ -74,7 +74,7 @@ public func XCTRuntimePrecondition(
_ message: @autoclosure () -> String = "",
file: StaticString = #filePath,
line: UInt = #line,
_ expression: @escaping () async -> Void
_ expression: @escaping @Sendable () async -> Void
) throws {
let fulfillmentCount = Counter()
let xctRuntimeAssertionId = setupXCTRuntimeAssertionInjector(
Expand Down
Loading