Skip to content

Commit 52b1f3d

Browse files
Merge pull request #21 from ZirgVoice/concurrency
Concurrency
2 parents c6129d9 + 0af209a commit 52b1f3d

File tree

11 files changed

+1218
-19
lines changed

11 files changed

+1218
-19
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ jobs:
6161
runs-on: ubuntu-22.04
6262
strategy:
6363
matrix:
64-
swift: ["5.7", "5.8", "5.9", "5.10"]
64+
swift: ["5.9", "5.10"]
6565
steps:
6666
- uses: swift-actions/setup-swift@v2
6767
with:

Package.resolved

Lines changed: 65 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,36 @@
1-
// swift-tools-version:5.0
1+
// swift-tools-version:5.9
22
// The swift-tools-version declares the minimum version of Swift required to build this package.
33

44
import PackageDescription
55

66
let package = Package(
77
name: "DataLoader",
8+
platforms: [.macOS(.v12), .iOS(.v15), .tvOS(.v15), .watchOS(.v8)],
89
products: [
910
.library(name: "DataLoader", targets: ["DataLoader"]),
11+
.library(name: "AsyncDataLoader", targets: ["AsyncDataLoader"]),
1012
],
1113
dependencies: [
14+
.package(url: "https://github.com/apple/swift-algorithms.git", from: "1.0.0"),
15+
.package(url: "https://github.com/adam-fowler/async-collections", from: "0.0.1"),
1216
.package(url: "https://github.com/apple/swift-nio.git", from: "2.0.0"),
1317
],
1418
targets: [
15-
.target(name: "DataLoader", dependencies: ["NIO", "NIOConcurrencyHelpers"]),
19+
.target(
20+
name: "DataLoader",
21+
dependencies: [
22+
.product(name: "NIO", package: "swift-nio"),
23+
.product(name: "NIOConcurrencyHelpers", package: "swift-nio"),
24+
]
25+
),
26+
.target(
27+
name: "AsyncDataLoader",
28+
dependencies: [
29+
.product(name: "Algorithms", package: "swift-algorithms"),
30+
.product(name: "AsyncCollections", package: "async-collections"),
31+
]
32+
),
1633
.testTarget(name: "DataLoaderTests", dependencies: ["DataLoader"]),
17-
],
18-
swiftLanguageVersions: [.v5]
34+
.testTarget(name: "AsyncDataLoaderTests", dependencies: ["AsyncDataLoader"]),
35+
]
1936
)
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
actor Channel<Success: Sendable, Failure: Error>: Sendable {
2+
private var state = State<Success, Failure>()
3+
}
4+
5+
extension Channel {
6+
@discardableResult
7+
func fulfill(_ value: Success) async -> Bool {
8+
if await state.result == nil {
9+
await state.setResult(result: value)
10+
11+
for waiters in await state.waiters {
12+
waiters.resume(returning: value)
13+
}
14+
15+
await state.removeAllWaiters()
16+
17+
return false
18+
}
19+
20+
return true
21+
}
22+
23+
@discardableResult
24+
func fail(_ failure: Failure) async -> Bool {
25+
if await state.failure == nil {
26+
await state.setFailure(failure: failure)
27+
28+
for waiters in await state.waiters {
29+
waiters.resume(throwing: failure)
30+
}
31+
32+
await state.removeAllWaiters()
33+
34+
return false
35+
}
36+
37+
return true
38+
}
39+
40+
var value: Success {
41+
get async throws {
42+
try await withCheckedThrowingContinuation { continuation in
43+
Task {
44+
if let result = await state.result {
45+
continuation.resume(returning: result)
46+
} else if let failure = await self.state.failure {
47+
continuation.resume(throwing: failure)
48+
} else {
49+
await state.appendWaiters(waiters: continuation)
50+
}
51+
}
52+
}
53+
}
54+
}
55+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
typealias Waiter<Success, Failure> = CheckedContinuation<Success, Error>
2+
3+
actor State<Success, Failure> {
4+
var waiters = [Waiter<Success, Failure>]()
5+
var result: Success?
6+
var failure: Failure?
7+
}
8+
9+
extension State {
10+
func setResult(result: Success) {
11+
self.result = result
12+
}
13+
14+
func setFailure(failure: Failure) {
15+
self.failure = failure
16+
}
17+
18+
func appendWaiters(waiters: Waiter<Success, Failure>...) {
19+
self.waiters.append(contentsOf: waiters)
20+
}
21+
22+
func removeAllWaiters() {
23+
waiters.removeAll()
24+
}
25+
}

0 commit comments

Comments
 (0)