Alternatively you could also write your own async-await friendlier semaphore (though this needs to be modified if you want to support cancellation scenarios etc.)
actor Semaphore {
private var count: Int
private var waiters: [CheckedContinuation<Void, Never>] = []
init(count: Int = 0) {
self.count = count
}
func wait() async {
count -= 1
if count >= 0 { return }
await withCheckedContinuation {
waiters.append($0)
}
}
func release(count: Int = 1) {
assert(count >= 1)
self.count += count
for _ in 0..<count {
if waiters.isEmpty { return }
waiters.removeFirst().resume()
}
}
}