@@ -41,7 +41,8 @@ struct MergeStateMachine<
41
41
buffer: Deque < Element > ,
42
42
upstreamContinuations: [ UnsafeContinuation < Void , Error > ] ,
43
43
upstreamsFinished: Int ,
44
- downstreamContinuation: UnsafeContinuation < Element ? , Error > ?
44
+ downstreamContinuation: UnsafeContinuation < Element ? , Error > ? ,
45
+ cancelled: Bool
45
46
)
46
47
47
48
/// The state once any of the upstream sequences threw an `Error`.
@@ -100,11 +101,11 @@ struct MergeStateMachine<
100
101
// Nothing to do here. No demand was signalled until now
101
102
return . none
102
103
103
- case . merging( _, _, _, _, . some) :
104
+ case . merging( _, _, _, _, . some, _ ) :
104
105
// An iterator was deinitialized while we have a suspended continuation.
105
106
preconditionFailure ( " Internal inconsistency current state \( self . state) and received iteratorDeinitialized() " )
106
107
107
- case let . merging( task, _, upstreamContinuations, _, . none) :
108
+ case let . merging( task, _, upstreamContinuations, _, . none, _ ) :
108
109
// The iterator was dropped which signals that the consumer is finished.
109
110
// We can transition to finished now and need to clean everything up.
110
111
state = . finished
@@ -142,7 +143,8 @@ struct MergeStateMachine<
142
143
buffer: . init( ) ,
143
144
upstreamContinuations: [ ] , // This should reserve capacity in the variadic generics case
144
145
upstreamsFinished: 0 ,
145
- downstreamContinuation: nil
146
+ downstreamContinuation: nil ,
147
+ cancelled: false
146
148
)
147
149
148
150
case . merging, . upstreamFailure, . finished:
@@ -175,11 +177,11 @@ struct MergeStateMachine<
175
177
// Child tasks are only created after we transitioned to `merging`
176
178
preconditionFailure ( " Internal inconsistency current state \( self . state) and received childTaskSuspended() " )
177
179
178
- case . merging( _, _, _, _, . some) :
180
+ case . merging( _, _, _, _, . some, _ ) :
179
181
// We have outstanding demand so request the next element
180
182
return . resumeContinuation( upstreamContinuation: continuation)
181
183
182
- case . merging( let task, let buffer, var upstreamContinuations, let upstreamsFinished, . none) :
184
+ case . merging( let task, let buffer, var upstreamContinuations, let upstreamsFinished, . none, let cancelled ) :
183
185
// There is no outstanding demand from the downstream
184
186
// so we are storing the continuation and resume it once there is demand.
185
187
state = . modifying
@@ -191,7 +193,8 @@ struct MergeStateMachine<
191
193
buffer: buffer,
192
194
upstreamContinuations: upstreamContinuations,
193
195
upstreamsFinished: upstreamsFinished,
194
- downstreamContinuation: nil
196
+ downstreamContinuation: nil ,
197
+ cancelled: cancelled
195
198
)
196
199
197
200
return . none
@@ -236,7 +239,7 @@ struct MergeStateMachine<
236
239
// Child tasks that are producing elements are only created after we transitioned to `merging`
237
240
preconditionFailure ( " Internal inconsistency current state \( self . state) and received elementProduced() " )
238
241
239
- case let . merging( task, buffer, upstreamContinuations, upstreamsFinished, . some( downstreamContinuation) ) :
242
+ case let . merging( task, buffer, upstreamContinuations, upstreamsFinished, . some( downstreamContinuation) , cancelled ) :
240
243
// We produced an element and have an outstanding downstream continuation
241
244
// this means we can go right ahead and resume the continuation with that element
242
245
precondition ( buffer. isEmpty, " We are holding a continuation so the buffer must be empty " )
@@ -246,15 +249,16 @@ struct MergeStateMachine<
246
249
buffer: buffer,
247
250
upstreamContinuations: upstreamContinuations,
248
251
upstreamsFinished: upstreamsFinished,
249
- downstreamContinuation: nil
252
+ downstreamContinuation: nil ,
253
+ cancelled: cancelled
250
254
)
251
255
252
256
return . resumeContinuation(
253
257
downstreamContinuation: downstreamContinuation,
254
258
element: element
255
259
)
256
260
257
- case . merging( let task, var buffer, let upstreamContinuations, let upstreamsFinished, . none) :
261
+ case . merging( let task, var buffer, let upstreamContinuations, let upstreamsFinished, . none, let cancelled ) :
258
262
// There is not outstanding downstream continuation so we must buffer the element
259
263
// This happens if we race our upstream sequences to produce elements
260
264
// and the _losers_ are signalling their produced element
@@ -267,7 +271,8 @@ struct MergeStateMachine<
267
271
buffer: buffer,
268
272
upstreamContinuations: upstreamContinuations,
269
273
upstreamsFinished: upstreamsFinished,
270
- downstreamContinuation: nil
274
+ downstreamContinuation: nil ,
275
+ cancelled: cancelled
271
276
)
272
277
273
278
return . none
@@ -310,7 +315,7 @@ struct MergeStateMachine<
310
315
case . initial:
311
316
preconditionFailure ( " Internal inconsistency current state \( self . state) and received upstreamFinished() " )
312
317
313
- case . merging( let task, let buffer, let upstreamContinuations, var upstreamsFinished, let . some( downstreamContinuation) ) :
318
+ case . merging( let task, let buffer, let upstreamContinuations, var upstreamsFinished, let . some( downstreamContinuation) , let cancelled ) :
314
319
// One of the upstreams finished
315
320
precondition ( buffer. isEmpty, " We are holding a continuation so the buffer must be empty " )
316
321
@@ -335,13 +340,14 @@ struct MergeStateMachine<
335
340
buffer: buffer,
336
341
upstreamContinuations: upstreamContinuations,
337
342
upstreamsFinished: upstreamsFinished,
338
- downstreamContinuation: downstreamContinuation
343
+ downstreamContinuation: downstreamContinuation,
344
+ cancelled: cancelled
339
345
)
340
346
341
347
return . none
342
348
}
343
349
344
- case . merging( let task, let buffer, let upstreamContinuations, var upstreamsFinished, . none) :
350
+ case . merging( let task, let buffer, let upstreamContinuations, var upstreamsFinished, . none, let cancelled ) :
345
351
// First we increment our counter of finished upstreams
346
352
upstreamsFinished += 1
347
353
@@ -350,7 +356,8 @@ struct MergeStateMachine<
350
356
buffer: buffer,
351
357
upstreamContinuations: upstreamContinuations,
352
358
upstreamsFinished: upstreamsFinished,
353
- downstreamContinuation: nil
359
+ downstreamContinuation: nil ,
360
+ cancelled: cancelled
354
361
)
355
362
356
363
if upstreamsFinished == self . numberOfUpstreamSequences {
@@ -402,7 +409,7 @@ struct MergeStateMachine<
402
409
case . initial:
403
410
preconditionFailure ( " Internal inconsistency current state \( self . state) and received upstreamThrew() " )
404
411
405
- case let . merging( task, buffer, upstreamContinuations, _, . some( downstreamContinuation) ) :
412
+ case let . merging( task, buffer, upstreamContinuations, _, . some( downstreamContinuation) , _ ) :
406
413
// An upstream threw an error and we have a downstream continuation.
407
414
// We just need to resume the downstream continuation with the error and cancel everything
408
415
precondition ( buffer. isEmpty, " We are holding a continuation so the buffer must be empty " )
@@ -417,7 +424,7 @@ struct MergeStateMachine<
417
424
upstreamContinuations: upstreamContinuations
418
425
)
419
426
420
- case let . merging( task, buffer, upstreamContinuations, _, . none) :
427
+ case let . merging( task, buffer, upstreamContinuations, _, . none, _ ) :
421
428
// An upstream threw an error and we don't have a downstream continuation.
422
429
// We need to store the error and wait for the downstream to consume the
423
430
// rest of the buffer and the error. However, we can already cancel the task
@@ -454,10 +461,7 @@ struct MergeStateMachine<
454
461
upstreamContinuations: [ UnsafeContinuation < Void , Error > ]
455
462
)
456
463
/// Indicates that the task and the upstream continuations should be cancelled.
457
- case cancelTaskAndUpstreamContinuations(
458
- task: Task < Void , Never > ,
459
- upstreamContinuations: [ UnsafeContinuation < Void , Error > ]
460
- )
464
+ case cancelTask( Task < Void , Never > )
461
465
/// Indicates that nothing should be done.
462
466
case none
463
467
}
@@ -471,26 +475,21 @@ struct MergeStateMachine<
471
475
472
476
return . none
473
477
474
- case let . merging( task, _ , upstreamContinuations, _ , . some ( downstreamContinuation) ) :
475
- // The downstream Task got cancelled so we need to cancel our upstream Task
476
- // and resume all continuations. We can also transition to finished.
477
- state = . finished
478
+ case let . merging( task, buffer , upstreamContinuations, upstreamFinished , downstreamContinuation, cancelled ) :
479
+ guard ! cancelled else {
480
+ return . none
481
+ }
478
482
479
- return . resumeDownstreamContinuationWithNilAndCancelTaskAndUpstreamContinuations(
480
- downstreamContinuation: downstreamContinuation,
483
+ self . state = . merging(
481
484
task: task,
482
- upstreamContinuations: upstreamContinuations
485
+ buffer: buffer,
486
+ upstreamContinuations: upstreamContinuations,
487
+ upstreamsFinished: upstreamFinished,
488
+ downstreamContinuation: downstreamContinuation,
489
+ cancelled: true
483
490
)
484
491
485
- case let . merging( task, _, upstreamContinuations, _, . none) :
486
- // The downstream Task got cancelled so we need to cancel our upstream Task
487
- // and resume all continuations. We can also transition to finished.
488
- state = . finished
489
-
490
- return . cancelTaskAndUpstreamContinuations(
491
- task: task,
492
- upstreamContinuations: upstreamContinuations
493
- )
492
+ return . cancelTask( task)
494
493
495
494
case . upstreamFailure:
496
495
// An upstream already threw and we cancelled everything already.
@@ -531,11 +530,11 @@ struct MergeStateMachine<
531
530
// We are transitioning to merging in the taskStarted method.
532
531
return . startTaskAndSuspendDownstreamTask( base1, base2, base3)
533
532
534
- case . merging( _, _, _, _, . some) :
533
+ case . merging( _, _, _, _, . some, _ ) :
535
534
// We have multiple AsyncIterators iterating the sequence
536
535
preconditionFailure ( " Internal inconsistency current state \( self . state) and received next() " )
537
536
538
- case . merging( let task, var buffer, let upstreamContinuations, let upstreamsFinished, . none) :
537
+ case . merging( let task, var buffer, let upstreamContinuations, let upstreamsFinished, . none, let cancelled ) :
539
538
state = . modifying
540
539
541
540
if let element = buffer. popFirst ( ) {
@@ -545,7 +544,8 @@ struct MergeStateMachine<
545
544
buffer: buffer,
546
545
upstreamContinuations: upstreamContinuations,
547
546
upstreamsFinished: upstreamsFinished,
548
- downstreamContinuation: nil
547
+ downstreamContinuation: nil ,
548
+ cancelled: cancelled
549
549
)
550
550
551
551
return . returnElement( . success( element) )
@@ -556,7 +556,8 @@ struct MergeStateMachine<
556
556
buffer: buffer,
557
557
upstreamContinuations: upstreamContinuations,
558
558
upstreamsFinished: upstreamsFinished,
559
- downstreamContinuation: nil
559
+ downstreamContinuation: nil ,
560
+ cancelled: cancelled
560
561
)
561
562
562
563
return . suspendDownstreamTask
@@ -601,21 +602,22 @@ struct MergeStateMachine<
601
602
mutating func next( for continuation: UnsafeContinuation < Element ? , Error > ) -> NextForAction {
602
603
switch state {
603
604
case . initial,
604
- . merging( _, _, _, _, . some) ,
605
+ . merging( _, _, _, _, . some, _ ) ,
605
606
. upstreamFailure,
606
607
. finished:
607
608
// All other states are handled by `next` already so we should never get in here with
608
609
// any of those
609
610
preconditionFailure ( " Internal inconsistency current state \( self . state) and received next(for:) " )
610
611
611
- case let . merging( task, buffer, upstreamContinuations, upstreamsFinished, . none) :
612
+ case let . merging( task, buffer, upstreamContinuations, upstreamsFinished, . none, cancelled ) :
612
613
// We suspended the task and need signal the upstreams
613
614
state = . merging(
614
615
task: task,
615
616
buffer: buffer,
616
617
upstreamContinuations: [ ] , // TODO: don't alloc new array here
617
618
upstreamsFinished: upstreamsFinished,
618
- downstreamContinuation: continuation
619
+ downstreamContinuation: continuation,
620
+ cancelled: cancelled
619
621
)
620
622
621
623
return . resumeUpstreamContinuations(
0 commit comments