Skip to content
This repository was archived by the owner on Aug 29, 2022. It is now read-only.

Commit 9cb92c4

Browse files
committed
Update andThen progress expansion to not leap backward by too much
1 parent 42b8a7a commit 9cb92c4

File tree

5 files changed

+34
-17
lines changed

5 files changed

+34
-17
lines changed

Sources/Task/TaskAndThen.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ extension TaskProtocol {
4343
/// - see: FutureProtocol.andThen(upon:start:)
4444
public func andThen<NewTask: TaskProtocol>(upon executor: Executor, start startNextTask: @escaping(Success) throws -> NewTask) -> Task<NewTask.Success> {
4545
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
46-
let chain = TaskChain(continuingWith: self)
46+
let chain = TaskChain(andThenFrom: self)
4747
#else
4848
let cancellationToken = Deferred<Void>()
4949
#endif

Sources/Task/TaskChain.swift

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,12 @@ struct TaskChain {
1919
/// The default work unit count for a single call to a `Task` initializer or
2020
/// chaining method.
2121
private static let singleUnit = Int64(1)
22+
/// The work unit count applied when a chaining method may later determine
23+
/// a higher or lower unit count.
24+
private static let undeterminedUnit = Int64(8)
2225
/// The work unit count when a `Task` initializer or chaining method accepts
2326
/// an user-provided `Progress` instance.
24-
private static let explicitChildUnitCount = Int64(100)
27+
private static let explicitChildUnitCount = Int64(20)
2528

2629
/// Marker class representing the start of a task chain.
2730
///
@@ -90,8 +93,8 @@ struct TaskChain {
9093
self.root = root
9194
self.effectiveProgress = root
9295
} else {
93-
// Create a "root" progress for the task and its follow-up steps.
94-
// If the initial operation provides progress, give it a 100x slice.
96+
// Create a "root" progress for the task and its follow-up steps. If
97+
// the initial operation provides progress, give it a larger slice.
9598
let unitCount = customProgress == nil ? TaskChain.singleUnit : TaskChain.explicitChildUnitCount
9699
self.root = Root()
97100
self.root.totalUnitCount = unitCount
@@ -107,17 +110,17 @@ struct TaskChain {
107110

108111
/// Locates or creates the root of a task chain, then increments its
109112
/// total units in preparation for a follow-up operation to be performed.
110-
init<Wrapped: TaskProtocol>(continuingWith wrapped: Wrapped) {
113+
private init<Wrapped: TaskProtocol>(continuingFrom wrapped: Wrapped, pendingUnitCount: Int64) {
111114
if let task = wrapped as? Task<Wrapped.Success>, let root = task.progress as? Root {
112115
// If `wrapped` is a Task created normally, reuse the progress root;
113116
// this `map` or `andThen` builds on that progress.
117+
root.totalUnitCount += pendingUnitCount
114118
self.root = root
115-
self.root.totalUnitCount += TaskChain.singleUnit
116119
self.effectiveProgress = root
117120
} else {
118121
// If `wrapped` is a `Future` or something else, start a new chain.
119122
self.root = Root()
120-
self.root.totalUnitCount = TaskChain.singleUnit * 2
123+
self.root.totalUnitCount = TaskChain.singleUnit + pendingUnitCount
121124
self.effectiveProgress = root
122125

123126
root.monitorCompletion(of: wrapped, withPendingUnitCount: TaskChain.singleUnit)
@@ -126,9 +129,15 @@ struct TaskChain {
126129

127130
// MARK: -
128131

132+
/// Locates or creates the root of a task chain, then increments its
133+
/// total units in preparation for a follow-up operation to be performed.
134+
init<Wrapped: TaskProtocol>(mapFrom wrapped: Wrapped) {
135+
self.init(continuingFrom: wrapped, pendingUnitCount: TaskChain.singleUnit)
136+
}
137+
129138
/// The handler passed to `map` can use implicit progress reporting.
130139
/// During the handler, the first `Progress` object created using
131-
/// `parent: .current()` will be given a 100x slice of the task chain on
140+
/// `parent: .current()` will be given a larger slice of the task chain on
132141
/// macOS 10.11, iOS 9, and above.
133142
func beginMap() {
134143
root.expandsAddedChildren = true
@@ -143,22 +152,29 @@ struct TaskChain {
143152

144153
// MARK: -
145154

155+
/// Locates or creates the root of a task chain, then increments its
156+
/// total units in preparation for a follow-up operation to be performed.
157+
init<Wrapped: TaskProtocol>(andThenFrom wrapped: Wrapped) {
158+
self.init(continuingFrom: wrapped, pendingUnitCount: TaskChain.undeterminedUnit)
159+
}
160+
146161
/// The handler passed to `andThen` uses explicit progress reporting.
147162
/// After returning a from the handler, locate or create a representative
148163
/// progress and attach it to the root. If this next step provides custom
149-
/// progress, give it a 100x slice.
164+
/// progress, give it a larger slice.
150165
func beginAndThen() {
151166
Root.activeStack.append(root)
152167
}
153168

154169
/// See `beginAndThen`.
155170
func commitAndThen<Wrapped: TaskProtocol>(with wrapped: Wrapped) {
156-
if let task = wrapped as? Task<Wrapped.Success> {
157-
let pendingUnitCount = task.progress.wasGeneratedByTask ? TaskChain.singleUnit : TaskChain.explicitChildUnitCount
158-
root.totalUnitCount += pendingUnitCount - TaskChain.singleUnit
159-
root.monitorChild(task.progress, withPendingUnitCount: pendingUnitCount)
171+
let wrappedProgress = (wrapped as? Task<Wrapped.Success>)?.progress
172+
let pendingUnitCount = wrappedProgress?.wasGeneratedByTask == false ? TaskChain.explicitChildUnitCount : TaskChain.singleUnit
173+
root.totalUnitCount += pendingUnitCount - TaskChain.undeterminedUnit
174+
if let wrappedProgress = wrappedProgress {
175+
root.monitorChild(wrappedProgress, withPendingUnitCount: pendingUnitCount)
160176
} else {
161-
root.monitorCompletion(of: wrapped, uponCancel: wrapped.cancel, withPendingUnitCount: TaskChain.singleUnit)
177+
root.monitorCompletion(of: wrapped, uponCancel: wrapped.cancel, withPendingUnitCount: pendingUnitCount)
162178
}
163179
Root.activeStack.removeLast()
164180
}
@@ -168,6 +184,7 @@ struct TaskChain {
168184
func flushAndThen() {
169185
root.becomeCurrent(withPendingUnitCount: TaskChain.singleUnit)
170186
root.resignCurrent()
187+
root.totalUnitCount += TaskChain.singleUnit - TaskChain.undeterminedUnit
171188
Root.activeStack.removeLast()
172189
}
173190
}

Sources/Task/TaskFallback.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ extension TaskProtocol {
4242
/// - see: FutureProtocol.andThen(upon:start:)
4343
public func fallback<NewTask: TaskProtocol>(upon executor: Executor, to restartTask: @escaping(Failure) throws -> NewTask) -> Task<Success> where NewTask.Success == Success {
4444
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
45-
let chain = TaskChain(continuingWith: self)
45+
let chain = TaskChain(andThenFrom: self)
4646
#else
4747
let cancellationToken = Deferred<Void>()
4848
#endif

Sources/Task/TaskMap.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ extension TaskProtocol {
3939
/// - see: FutureProtocol.map(upon:transform:)
4040
public func map<NewSuccess>(upon executor: Executor, transform: @escaping(Success) throws -> NewSuccess) -> Task<NewSuccess> {
4141
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
42-
let chain = TaskChain(continuingWith: self)
42+
let chain = TaskChain(mapFrom: self)
4343
#endif
4444

4545
let future: Future = map(upon: executor) { (result) -> Task<NewSuccess>.Result in

Sources/Task/TaskRecovery.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ extension TaskProtocol {
4040
/// - see: FutureProtocol.map(upon:transform:)
4141
public func recover(upon executor: Executor, substituting substitution: @escaping(Failure) throws -> Success) -> Task<Success> {
4242
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
43-
let chain = TaskChain(continuingWith: self)
43+
let chain = TaskChain(andThenFrom: self)
4444
#endif
4545

4646
let future: Future = map(upon: executor) { (result) -> Task<Success>.Result in

0 commit comments

Comments
 (0)