From 55d5f7863513da28620654fcefe7b8e5b628d110 Mon Sep 17 00:00:00 2001 From: Rachel Brindle Date: Tue, 19 Mar 2024 09:11:13 -0700 Subject: [PATCH] Make the Polling Helpers Sendable (#1133) --- Sources/Nimble/Polling+AsyncAwait.swift | 2 +- Sources/Nimble/Utils/AsyncAwait.swift | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Sources/Nimble/Polling+AsyncAwait.swift b/Sources/Nimble/Polling+AsyncAwait.swift index 6adb153c0..cef8669e9 100644 --- a/Sources/Nimble/Polling+AsyncAwait.swift +++ b/Sources/Nimble/Polling+AsyncAwait.swift @@ -41,7 +41,7 @@ internal actor Poller { file: expression.location.file, line: expression.location.line, fnName: fnName) { - if self.updateMatcherResult(result: try await matcherRunner()) + if await self.updateMatcherResult(result: try await matcherRunner()) .toBoolean(expectation: style) { if matchStyle.isContinous { return .incomplete diff --git a/Sources/Nimble/Utils/AsyncAwait.swift b/Sources/Nimble/Utils/AsyncAwait.swift index 1e5884370..ba7513884 100644 --- a/Sources/Nimble/Utils/AsyncAwait.swift +++ b/Sources/Nimble/Utils/AsyncAwait.swift @@ -12,7 +12,7 @@ private let pollLeeway = NimbleTimeInterval.milliseconds(1) // Like PollResult, except it doesn't support objective-c exceptions. // Which is tolerable because Swift Concurrency doesn't support recording objective-c exceptions. -internal enum AsyncPollResult { +internal enum AsyncPollResult: Sendable { /// Incomplete indicates None (aka - this value hasn't been fulfilled yet) case incomplete /// TimedOut indicates the result reached its defined timeout limit before returning @@ -57,10 +57,10 @@ internal enum AsyncPollResult { // Inspired by swift-async-algorithm's AsyncChannel, but massively simplified // especially given Nimble's usecase. // AsyncChannel: https://github.com/apple/swift-async-algorithms/blob/main/Sources/AsyncAlgorithms/Channels/AsyncChannel.swift -internal actor AsyncPromise { +internal actor AsyncPromise { private let storage = Storage() - private final class Storage { + private final class Storage: @unchecked Sendable { private var continuations: [UnsafeContinuation] = [] private var value: T? // Yes, this is not the fastest lock, but it's platform independent, @@ -131,7 +131,7 @@ internal actor AsyncPromise { /// checked. /// /// In addition, stopping the run loop is used to halt code executed on the main run loop. -private func timeout(timeoutQueue: DispatchQueue, timeoutInterval: NimbleTimeInterval, forcefullyAbortTimeout: NimbleTimeInterval) async -> AsyncPollResult { +private func timeout(timeoutQueue: DispatchQueue, timeoutInterval: NimbleTimeInterval, forcefullyAbortTimeout: NimbleTimeInterval) async -> AsyncPollResult { do { try await Task.sleep(nanoseconds: timeoutInterval.nanoseconds) } catch {} @@ -165,7 +165,7 @@ private func timeout(timeoutQueue: DispatchQueue, timeoutInterval: NimbleTime return await promise.value } -private func poll(_ pollInterval: NimbleTimeInterval, expression: @escaping () async throws -> PollStatus) async -> AsyncPollResult { +private func poll(_ pollInterval: NimbleTimeInterval, expression: @escaping @Sendable () async throws -> PollStatus) async -> AsyncPollResult { for try await _ in AsyncTimerSequence(interval: pollInterval) { do { if case .finished(let result) = try await expression() { @@ -199,7 +199,7 @@ private func runPoller( pollInterval: NimbleTimeInterval, awaiter: Awaiter, fnName: String = #function, file: FileString = #file, line: UInt = #line, - expression: @escaping () async throws -> PollStatus + expression: @escaping @Sendable () async throws -> PollStatus ) async -> AsyncPollResult { awaiter.waitLock.acquireWaitingLock( fnName, @@ -258,7 +258,7 @@ private func runAwaitTrigger( timeoutInterval: NimbleTimeInterval, leeway: NimbleTimeInterval, file: FileString, line: UInt, - _ closure: @escaping (@escaping (T) -> Void) async throws -> Void + _ closure: @escaping @Sendable (@escaping @Sendable (T) -> Void) async throws -> Void ) async -> AsyncPollResult { let timeoutQueue = awaiter.timeoutQueue let completionCount = Box(value: 0) @@ -309,7 +309,7 @@ internal func performBlock( timeoutInterval: NimbleTimeInterval, leeway: NimbleTimeInterval, file: FileString, line: UInt, - _ closure: @escaping (@escaping (T) -> Void) async throws -> Void + _ closure: @escaping @Sendable (@escaping @Sendable (T) -> Void) async throws -> Void ) async -> AsyncPollResult { await runAwaitTrigger( awaiter: NimbleEnvironment.activeInstance.awaiter, @@ -324,7 +324,7 @@ internal func pollBlock( file: FileString, line: UInt, fnName: String = #function, - expression: @escaping () async throws -> PollStatus) async -> AsyncPollResult { + expression: @escaping @Sendable () async throws -> PollStatus) async -> AsyncPollResult { await runPoller( timeoutInterval: timeoutInterval, pollInterval: pollInterval,