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

Make the Polling Helpers Sendable #1133

Merged
merged 1 commit into from
Mar 19, 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: 1 addition & 1 deletion Sources/Nimble/Polling+AsyncAwait.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ internal actor Poller<T> {
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
Expand Down
18 changes: 9 additions & 9 deletions Sources/Nimble/Utils/AsyncAwait.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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<T> {
internal enum AsyncPollResult<T: Sendable>: 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
Expand Down Expand Up @@ -57,10 +57,10 @@ internal enum AsyncPollResult<T> {
// 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<T> {
internal actor AsyncPromise<T: Sendable> {
private let storage = Storage()

private final class Storage {
private final class Storage: @unchecked Sendable {
private var continuations: [UnsafeContinuation<T, Never>] = []
private var value: T?
// Yes, this is not the fastest lock, but it's platform independent,
Expand Down Expand Up @@ -131,7 +131,7 @@ internal actor AsyncPromise<T> {
/// checked.
///
/// In addition, stopping the run loop is used to halt code executed on the main run loop.
private func timeout<T>(timeoutQueue: DispatchQueue, timeoutInterval: NimbleTimeInterval, forcefullyAbortTimeout: NimbleTimeInterval) async -> AsyncPollResult<T> {
private func timeout<T: Sendable>(timeoutQueue: DispatchQueue, timeoutInterval: NimbleTimeInterval, forcefullyAbortTimeout: NimbleTimeInterval) async -> AsyncPollResult<T> {
do {
try await Task.sleep(nanoseconds: timeoutInterval.nanoseconds)
} catch {}
Expand Down Expand Up @@ -165,7 +165,7 @@ private func timeout<T>(timeoutQueue: DispatchQueue, timeoutInterval: NimbleTime
return await promise.value
}

private func poll(_ pollInterval: NimbleTimeInterval, expression: @escaping () async throws -> PollStatus) async -> AsyncPollResult<Bool> {
private func poll(_ pollInterval: NimbleTimeInterval, expression: @escaping @Sendable () async throws -> PollStatus) async -> AsyncPollResult<Bool> {
for try await _ in AsyncTimerSequence(interval: pollInterval) {
do {
if case .finished(let result) = try await expression() {
Expand Down Expand Up @@ -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<Bool> {
awaiter.waitLock.acquireWaitingLock(
fnName,
Expand Down Expand Up @@ -258,7 +258,7 @@ private func runAwaitTrigger<T>(
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<T> {
let timeoutQueue = awaiter.timeoutQueue
let completionCount = Box(value: 0)
Expand Down Expand Up @@ -309,7 +309,7 @@ internal func performBlock<T>(
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<T> {
await runAwaitTrigger(
awaiter: NimbleEnvironment.activeInstance.awaiter,
Expand All @@ -324,7 +324,7 @@ internal func pollBlock(
file: FileString,
line: UInt,
fnName: String = #function,
expression: @escaping () async throws -> PollStatus) async -> AsyncPollResult<Bool> {
expression: @escaping @Sendable () async throws -> PollStatus) async -> AsyncPollResult<Bool> {
await runPoller(
timeoutInterval: timeoutInterval,
pollInterval: pollInterval,
Expand Down
Loading