Skip to content

Commit

Permalink
Listening + IdentifiableContinuation
Browse files Browse the repository at this point in the history
  • Loading branch information
swhitty committed Apr 12, 2024
1 parent 4db6bf2 commit 20ebae4
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 16 deletions.
6 changes: 5 additions & 1 deletion FlyingFox/Sources/HTTPServer+Listening.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,16 @@ extension HTTPServer {
private func doWaitUntilListening() async throws {
guard !isListening else { return }
try await withIdentifiableThrowingContinuation(isolation: self) {
waiting[$0.id] = $0
appendContinuation($0)
} onCancel: { id in
Task { await self.cancelContinuation(with: id) }
}
}

private func appendContinuation(_ continuation: Continuation) {
waiting[continuation.id] = continuation
}

private func cancelContinuation(with id: Continuation.ID) {
if let continuation = waiting.removeValue(forKey: id) {
continuation.resume(throwing: CancellationError())
Expand Down
12 changes: 12 additions & 0 deletions FlyingFox/Tests/HTTPServerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,18 @@ final class HTTPServerTests: XCTestCase {
}
}

func testWaitsUntilListening() async throws {
let server = HTTPServer.make()
let task = Task { try await server.waitUntilListening() }
try await Task.sleep(seconds: 0.1)

try await startServer(server)

await AsyncAssertNoThrow(
try await task.result.get()
)
}

func testThrowsError_WhenSocketAlreadyListening() async throws {
let server = HTTPServer.make(port: 42185)
let socket = try await server.makeSocketAndListen()
Expand Down
21 changes: 6 additions & 15 deletions FlyingSocks/Sources/SocketPool.swift
Original file line number Diff line number Diff line change
Expand Up @@ -156,34 +156,25 @@ public final actor SocketPool<Queue: EventQueue>: AsyncSocketPool {
state = .complete
waiting.cancellAll()
waiting = Waiting()
loop?.resume(throwing: CancellationError())
loop?.cancel()
loop = nil
}

typealias Continuation = CancellingContinuation<Void, SocketError>
private var loop: IdentifiableContinuation<Void, any Swift.Error>?
private var loop: CancellingContinuation<Void, Never>?
private var waiting = Waiting() {
didSet {
if !waiting.isEmpty, let continuation = loop {
continuation.resume()
loop = nil
}
}
}

private func suspendUntilContinuationsExist() async throws {
try await withIdentifiableThrowingContinuation(isolation: self) {
loop = $0
} onCancel: { id in
Task { await self.cancelLoopContinuation(with: id) }
}
}

private func cancelLoopContinuation(with id: IdentifiableContinuation<Void, any Swift.Error>.ID) {
if loop?.id == id {
loop?.resume(throwing: CancellationError())
loop = nil
}
let continuation = CancellingContinuation<Void, Never>()
loop = continuation
defer { loop = nil }
return try await continuation.value
}

private func appendContinuation(_ continuation: Continuation,
Expand Down

0 comments on commit 20ebae4

Please sign in to comment.