Skip to content

Commit 5cce99b

Browse files
committed
Make IndexTaskDescription protocol-based instead of enum-based
This simplifies the implementation.
1 parent 1fb087f commit 5cce99b

File tree

6 files changed

+62
-81
lines changed

6 files changed

+62
-81
lines changed

Sources/SemanticIndex/IndexTaskDescription.swift

Lines changed: 44 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -12,94 +12,72 @@
1212

1313
import SKCore
1414

15-
/// A task that either prepares targets or updates the index store for a set of files.
16-
public enum IndexTaskDescription: TaskDescriptionProtocol {
17-
case updateIndexStore(UpdateIndexStoreTaskDescription)
18-
case preparation(PreparationTaskDescription)
15+
/// Protocol of tasks that are executed on the index task scheduler.
16+
///
17+
/// It is assumed that `IndexTaskDescription` of different types are allowed to execute in parallel.
18+
protocol IndexTaskDescription: TaskDescriptionProtocol {
19+
/// A string that is unique to this type of `IndexTaskDescription`. It is used to produce unique IDs for tasks of
20+
/// different types in `AnyIndexTaskDescription`
21+
static var idPrefix: String { get }
22+
23+
var id: UInt32 { get }
24+
}
25+
26+
extension IndexTaskDescription {
27+
func dependencies(
28+
to currentlyExecutingTasks: [AnyIndexTaskDescription]
29+
) -> [TaskDependencyAction<AnyIndexTaskDescription>] {
30+
return self.dependencies(to: currentlyExecutingTasks.compactMap { $0.wrapped as? Self })
31+
.map {
32+
switch $0 {
33+
case .cancelAndRescheduleDependency(let td):
34+
return .cancelAndRescheduleDependency(AnyIndexTaskDescription(td))
35+
case .waitAndElevatePriorityOfDependency(let td):
36+
return .waitAndElevatePriorityOfDependency(AnyIndexTaskDescription(td))
37+
}
38+
}
39+
40+
}
41+
}
42+
43+
/// Type-erased wrapper of an `IndexTaskDescription`.
44+
public struct AnyIndexTaskDescription: TaskDescriptionProtocol {
45+
let wrapped: any IndexTaskDescription
46+
47+
init(_ wrapped: any IndexTaskDescription) {
48+
self.wrapped = wrapped
49+
}
1950

2051
public var isIdempotent: Bool {
21-
switch self {
22-
case .updateIndexStore(let taskDescription): return taskDescription.isIdempotent
23-
case .preparation(let taskDescription): return taskDescription.isIdempotent
24-
}
52+
return wrapped.isIdempotent
2553
}
2654

2755
public var estimatedCPUCoreCount: Int {
28-
switch self {
29-
case .updateIndexStore(let taskDescription): return taskDescription.estimatedCPUCoreCount
30-
case .preparation(let taskDescription): return taskDescription.estimatedCPUCoreCount
31-
}
56+
return wrapped.estimatedCPUCoreCount
3257
}
3358

3459
public var id: String {
35-
switch self {
36-
case .updateIndexStore(let taskDescription): return "indexing-\(taskDescription.id)"
37-
case .preparation(let taskDescription): return "preparation-\(taskDescription.id)"
38-
}
60+
return "\(type(of: wrapped).idPrefix)-\(wrapped.id)"
3961
}
4062

4163
public var description: String {
42-
switch self {
43-
case .updateIndexStore(let taskDescription): return taskDescription.description
44-
case .preparation(let taskDescription): return taskDescription.description
45-
}
64+
return wrapped.description
4665
}
4766

4867
public var redactedDescription: String {
49-
switch self {
50-
case .updateIndexStore(let taskDescription): return taskDescription.redactedDescription
51-
case .preparation(let taskDescription): return taskDescription.redactedDescription
52-
}
68+
return wrapped.redactedDescription
5369
}
5470

5571
public func execute() async {
56-
switch self {
57-
case .updateIndexStore(let taskDescription): return await taskDescription.execute()
58-
case .preparation(let taskDescription): return await taskDescription.execute()
59-
}
72+
return await wrapped.execute()
6073
}
6174

6275
/// Forward to the underlying task to compute the dependencies. Preparation and index tasks don't have any
6376
/// dependencies that are managed by `TaskScheduler`. `SemanticIndexManager` awaits the preparation of a target before
6477
/// indexing files within it.
6578
public func dependencies(
66-
to currentlyExecutingTasks: [IndexTaskDescription]
67-
) -> [TaskDependencyAction<IndexTaskDescription>] {
68-
switch self {
69-
case .updateIndexStore(let taskDescription):
70-
let currentlyExecutingTasks =
71-
currentlyExecutingTasks
72-
.compactMap { (currentlyExecutingTask) -> UpdateIndexStoreTaskDescription? in
73-
if case .updateIndexStore(let currentlyExecutingTask) = currentlyExecutingTask {
74-
return currentlyExecutingTask
75-
}
76-
return nil
77-
}
78-
return taskDescription.dependencies(to: currentlyExecutingTasks).map {
79-
switch $0 {
80-
case .waitAndElevatePriorityOfDependency(let td):
81-
return .waitAndElevatePriorityOfDependency(.updateIndexStore(td))
82-
case .cancelAndRescheduleDependency(let td):
83-
return .cancelAndRescheduleDependency(.updateIndexStore(td))
84-
}
85-
}
86-
case .preparation(let taskDescription):
87-
let currentlyExecutingTasks =
88-
currentlyExecutingTasks
89-
.compactMap { (currentlyExecutingTask) -> PreparationTaskDescription? in
90-
if case .preparation(let currentlyExecutingTask) = currentlyExecutingTask {
91-
return currentlyExecutingTask
92-
}
93-
return nil
94-
}
95-
return taskDescription.dependencies(to: currentlyExecutingTasks).map {
96-
switch $0 {
97-
case .waitAndElevatePriorityOfDependency(let td):
98-
return .waitAndElevatePriorityOfDependency(.preparation(td))
99-
case .cancelAndRescheduleDependency(let td):
100-
return .cancelAndRescheduleDependency(.preparation(td))
101-
}
102-
}
103-
}
79+
to currentlyExecutingTasks: [AnyIndexTaskDescription]
80+
) -> [TaskDependencyAction<AnyIndexTaskDescription>] {
81+
return wrapped.dependencies(to: currentlyExecutingTasks)
10482
}
10583
}

Sources/SemanticIndex/PreparationTaskDescription.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ private var preparationIDForLogging = AtomicUInt32(initialValue: 1)
2424
/// Describes a task to prepare a set of targets.
2525
///
2626
/// This task description can be scheduled in a `TaskScheduler`.
27-
public struct PreparationTaskDescription: TaskDescriptionProtocol {
27+
public struct PreparationTaskDescription: IndexTaskDescription {
28+
public static let idPrefix = "prepare"
29+
2830
public let id = preparationIDForLogging.fetchAndIncrement()
2931

3032
/// The targets that should be prepared.

Sources/SemanticIndex/SemanticIndexManager.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,20 +44,20 @@ public final actor SemanticIndexManager {
4444
/// The `TaskScheduler` that manages the scheduling of index tasks. This is shared among all `SemanticIndexManager`s
4545
/// in the process, to ensure that we don't schedule more index operations than processor cores from multiple
4646
/// workspaces.
47-
private let indexTaskScheduler: TaskScheduler<IndexTaskDescription>
47+
private let indexTaskScheduler: TaskScheduler<AnyIndexTaskDescription>
4848

4949
/// Callback that is called when an index task has finished.
5050
///
5151
/// Currently only used for testing.
52-
private let indexTaskDidFinish: (@Sendable (IndexTaskDescription) -> Void)?
52+
private let indexTaskDidFinish: (@Sendable (AnyIndexTaskDescription) -> Void)?
5353

5454
// MARK: - Public API
5555

5656
public init(
5757
index: UncheckedIndex,
5858
buildSystemManager: BuildSystemManager,
59-
indexTaskScheduler: TaskScheduler<IndexTaskDescription>,
60-
indexTaskDidFinish: (@Sendable (IndexTaskDescription) -> Void)?
59+
indexTaskScheduler: TaskScheduler<AnyIndexTaskDescription>,
60+
indexTaskDidFinish: (@Sendable (AnyIndexTaskDescription) -> Void)?
6161
) {
6262
self.index = index.checked(for: .modifiedFiles)
6363
self.buildSystemManager = buildSystemManager
@@ -133,12 +133,12 @@ public final actor SemanticIndexManager {
133133
private func prepare(targets: [ConfiguredTarget], priority: TaskPriority?) async {
134134
await self.indexTaskScheduler.schedule(
135135
priority: priority,
136-
.preparation(
136+
AnyIndexTaskDescription(
137137
PreparationTaskDescription(
138138
targetsToPrepare: targets,
139139
buildSystemManager: self.buildSystemManager,
140140
didFinishCallback: { [weak self] taskDescription in
141-
self?.indexTaskDidFinish?(.preparation(taskDescription))
141+
self?.indexTaskDidFinish?(AnyIndexTaskDescription(taskDescription))
142142
}
143143
)
144144
)
@@ -149,13 +149,13 @@ public final actor SemanticIndexManager {
149149
private func updateIndexStore(for files: [DocumentURI], priority: TaskPriority?) async {
150150
await self.indexTaskScheduler.schedule(
151151
priority: priority,
152-
.updateIndexStore(
152+
AnyIndexTaskDescription(
153153
UpdateIndexStoreTaskDescription(
154154
filesToIndex: Set(files),
155155
buildSystemManager: self.buildSystemManager,
156156
index: self.index.unchecked,
157157
didFinishCallback: { [weak self] taskDescription in
158-
self?.indexTaskDidFinish?(.updateIndexStore(taskDescription))
158+
self?.indexTaskDidFinish?(AnyIndexTaskDescription(taskDescription))
159159
}
160160
)
161161
)

Sources/SemanticIndex/UpdateIndexStoreTaskDescription.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ private nonisolated(unsafe) var updateIndexStoreIDForLogging = AtomicUInt32(init
2525
/// Describes a task to index a set of source files.
2626
///
2727
/// This task description can be scheduled in a `TaskScheduler`.
28-
public struct UpdateIndexStoreTaskDescription: TaskDescriptionProtocol {
28+
public struct UpdateIndexStoreTaskDescription: IndexTaskDescription {
29+
public static let idPrefix = "update-indexstore"
2930
public let id = updateIndexStoreIDForLogging.fetchAndIncrement()
3031

3132
/// The files that should be indexed.

Sources/SourceKitLSP/SourceKitLSPServer.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,7 @@ public actor SourceKitLSPServer {
454454
///
455455
/// Shared process-wide to ensure the scheduled index operations across multiple workspaces don't exceed the maximum
456456
/// number of processor cores that the user allocated to background indexing.
457-
private let indexTaskScheduler: TaskScheduler<IndexTaskDescription>
457+
private let indexTaskScheduler: TaskScheduler<AnyIndexTaskDescription>
458458

459459
private var packageLoadingWorkDoneProgress = WorkDoneProgressState(
460460
"SourceKitLSP.SourceKitLSPServer.reloadPackage",

Sources/SourceKitLSP/Workspace.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ public final class Workspace: Sendable {
8989
underlyingBuildSystem: BuildSystem?,
9090
index uncheckedIndex: UncheckedIndex?,
9191
indexDelegate: SourceKitIndexDelegate?,
92-
indexTaskScheduler: TaskScheduler<IndexTaskDescription>
92+
indexTaskScheduler: TaskScheduler<AnyIndexTaskDescription>
9393
) async {
9494
self.documentManager = documentManager
9595
self.buildSetup = options.buildSetup
@@ -142,7 +142,7 @@ public final class Workspace: Sendable {
142142
options: SourceKitLSPServer.Options,
143143
compilationDatabaseSearchPaths: [RelativePath],
144144
indexOptions: IndexOptions = IndexOptions(),
145-
indexTaskScheduler: TaskScheduler<IndexTaskDescription>,
145+
indexTaskScheduler: TaskScheduler<AnyIndexTaskDescription>,
146146
reloadPackageStatusCallback: @Sendable @escaping (ReloadPackageStatus) async -> Void
147147
) async throws {
148148
var buildSystem: BuildSystem? = nil
@@ -306,7 +306,7 @@ public struct IndexOptions: Sendable {
306306
/// A callback that is called when an index task finishes.
307307
///
308308
/// Intended for testing purposes.
309-
public var indexTaskDidFinish: (@Sendable (IndexTaskDescription) -> Void)?
309+
public var indexTaskDidFinish: (@Sendable (AnyIndexTaskDescription) -> Void)?
310310

311311
public init(
312312
indexStorePath: AbsolutePath? = nil,
@@ -315,7 +315,7 @@ public struct IndexOptions: Sendable {
315315
listenToUnitEvents: Bool = true,
316316
enableBackgroundIndexing: Bool = false,
317317
maxCoresPercentageToUseForBackgroundIndexing: Double = 1,
318-
indexTaskDidFinish: (@Sendable (IndexTaskDescription) -> Void)? = nil
318+
indexTaskDidFinish: (@Sendable (AnyIndexTaskDescription) -> Void)? = nil
319319
) {
320320
self.indexStorePath = indexStorePath
321321
self.indexDatabasePath = indexDatabasePath

0 commit comments

Comments
 (0)