Skip to content

Commit d90e8b8

Browse files
committed
feat: Implement DispatchQueue using Swift Concurrency.
1 parent 940349b commit d90e8b8

File tree

1 file changed

+84
-0
lines changed

1 file changed

+84
-0
lines changed
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2025 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
/// `DispatchQueue` is a drop-in replacement for the `DispatchQueue` implemented
14+
/// in Grand Central Dispatch. However, this class uses Swift Concurrency, instead of low-level threading API's.
15+
///
16+
/// The primary goal of this implementation is to enable WASM support for Dispatch.
17+
///
18+
/// Refer to documentation for the original [DispatchQueue](https://developer.apple.com/documentation/dispatch/dispatchqueue)
19+
/// for more details,
20+
@available(macOS 10.15, *)
21+
public class DispatchQueue: @unchecked Sendable {
22+
public static let main = DispatchQueue(isMain: true)
23+
24+
private static let _global = DispatchQueue()
25+
public static func global() -> DispatchQueue {
26+
Self._global
27+
}
28+
29+
public enum Attributes {
30+
case concurrent
31+
}
32+
33+
private let targetQueue: DispatchQueue?
34+
35+
/// Indicates whether calling context is running from the main DispatchQueue instance, or some other DispatchQueue instance.
36+
@TaskLocal public static var isMain = false
37+
38+
/// This is set during the initialization of the DispatchQueue, and controls whether `async` calls run on MainActor or not
39+
private let isMain: Bool
40+
private let label: String?
41+
private let attributes: DispatchQueue.Attributes?
42+
43+
public convenience init(
44+
label: String? = nil,
45+
attributes: DispatchQueue.Attributes? = nil,
46+
target: DispatchQueue? = nil
47+
) {
48+
self.init(isMain: false, label: label, attributes: attributes, target: target)
49+
}
50+
51+
private init(
52+
isMain: Bool,
53+
label: String? = nil,
54+
attributes: DispatchQueue.Attributes? = nil,
55+
target: DispatchQueue? = nil
56+
) {
57+
self.isMain = isMain
58+
self.label = label
59+
self.attributes = attributes
60+
self.targetQueue = target
61+
}
62+
63+
public func async(
64+
execute work: @escaping @Sendable @convention(block) () -> Void
65+
) {
66+
if let targetQueue, targetQueue !== self {
67+
// Recursively call this function on the target queue
68+
// until we reach a nil queue, or this queue.
69+
targetQueue.async(execute: work)
70+
} else {
71+
if isMain {
72+
Task { @MainActor [work] in
73+
DispatchQueue.$isMain.withValue(true) {
74+
work()
75+
}
76+
}
77+
} else {
78+
Task {
79+
work()
80+
}
81+
}
82+
}
83+
}
84+
}

0 commit comments

Comments
 (0)