44//
55// Created by Thibault Wittemberg on 31/12/2021.
66//
7+ import Foundation
78
89public extension AsyncSequences {
910 /// `Merge` is an AsyncSequence that merges several async sequences respecting
@@ -63,63 +64,89 @@ public struct AsyncMergeSequence<UpstreamAsyncSequence: AsyncSequence>: AsyncSeq
6364 }
6465
6566 public func makeAsyncIterator( ) -> Iterator {
66- return Iterator ( upstreamIterators : self . upstreamAsyncSequences. map { $0 . makeAsyncIterator ( ) } )
67+ return Iterator ( upstreamAsyncSequences : self . upstreamAsyncSequences)
6768 }
6869
6970 enum UpstreamElement {
7071 case element( Element )
7172 case finished
7273 }
7374
74- actor ElementCounter {
75- var counter = 0
76-
77- func increaseCounter( ) {
78- self . counter += 1
79- }
80-
81- func decreaseCounter( ) {
82- guard self . counter > 0 else { return }
83- self . counter -= 1
84- }
85-
86- func hasElement( ) -> Bool {
87- self . counter > 0
88- }
89- }
75+ // actor ElementCounter {
76+ // var counter = 0
77+ //
78+ // func increaseCounter() {
79+ // self.counter += 1
80+ // }
81+ //
82+ // func decreaseCounter() {
83+ // guard self.counter > 0 else { return }
84+ // self.counter -= 1
85+ // }
86+ //
87+ // func hasElement() -> Bool {
88+ // self.counter > 0
89+ // }
90+ // }
9091
9192 public struct Iterator : AsyncIteratorProtocol {
92- let sink = AsyncStreams . Passthrough < UpstreamElement > ( )
93- var sinkIterator : AsyncStreams . Passthrough < UpstreamElement > . AsyncIterator
94- let upstreamIterators : [ SharedAsyncIterator < UpstreamAsyncSequence . AsyncIterator > ]
95- let elementCounter = ElementCounter ( )
93+
94+ var downstreamIterator : AsyncStreams . Passthrough < UpstreamElement > . AsyncIterator
95+ let upstreamAsyncSequenceRegulators : [ ConcurrentAccessRegulator < UpstreamAsyncSequence > ]
96+ // let elementCounter = ElementCounter()
9697 var numberOfFinished = 0
9798
98- public init ( upstreamIterators: [ UpstreamAsyncSequence . AsyncIterator ] ) {
99- self . upstreamIterators = upstreamIterators. map { SharedAsyncIterator ( iterator: $0) }
100- self . sinkIterator = self . sink. makeAsyncIterator ( )
99+ public init ( upstreamAsyncSequences: [ UpstreamAsyncSequence ] ) {
100+ let downstreamStream = AsyncStreams . Passthrough < UpstreamElement > ( )
101+ self . downstreamIterator = downstreamStream. makeAsyncIterator ( )
102+ self . upstreamAsyncSequenceRegulators = upstreamAsyncSequences. map { upstreamAsyncSequence in
103+ var isAlreadyFinished = false
104+ return ConcurrentAccessRegulator (
105+ upstreamAsyncSequence,
106+ onNext: { element in
107+ if let nonNilElement = element {
108+ // await localElementCounter.increaseCounter()
109+ downstreamStream. send ( . element( nonNilElement) )
110+ return
111+ }
112+
113+ guard !isAlreadyFinished else { return }
114+
115+ isAlreadyFinished = true
116+ downstreamStream. send ( . finished)
117+ } ,
118+ onError: { error in
119+ downstreamStream. send ( termination: . failure( error) )
120+ } ,
121+ onCancel: {
122+ guard !isAlreadyFinished else { return }
123+ isAlreadyFinished = true
124+ downstreamStream. send ( . finished)
125+ } )
126+ }
101127 }
102128
103- mutating func nextElementFromSink ( ) async throws -> Element ? {
129+ mutating func nextElementFromDownstreamStream ( ) async throws -> Element ? {
104130 var noValue = true
105131 var value : Element ?
106132
107133 // we now have to eliminate the intermediate ".finished" values until the next
108134 // true value is found.
109135 // if every upstream iterator has finished, then the zipped async sequence is also finished
110136 while noValue {
111- guard let nextChildElement = try await self . sinkIterator . next ( ) else {
112- // the sink stream is finished, so is the zipped async sequence
137+ guard let nextChildElement = try await self . downstreamIterator . next ( ) else {
138+ // the downstream stream is finished, so is the zipped async sequence
113139 noValue = false
114140 value = nil
115141 break
116142 }
117143
118144 switch nextChildElement {
119145 case . finished:
146+
120147 self . numberOfFinished += 1
121148
122- if self . numberOfFinished == self . upstreamIterators . count {
149+ if self . numberOfFinished == self . upstreamAsyncSequenceRegulators . count {
123150 noValue = false
124151 value = nil
125152 break
@@ -128,7 +155,7 @@ public struct AsyncMergeSequence<UpstreamAsyncSequence: AsyncSequence>: AsyncSeq
128155 // nominal case: a next element is available
129156 noValue = false
130157 value = element
131- await self . elementCounter. decreaseCounter ( )
158+ // await self.elementCounter.decreaseCounter()
132159 }
133160 }
134161
@@ -138,57 +165,27 @@ public struct AsyncMergeSequence<UpstreamAsyncSequence: AsyncSequence>: AsyncSeq
138165 public mutating func next( ) async throws -> Element ? {
139166 guard !Task. isCancelled else { return nil }
140167
141- // before requesting elements from the upstream iterators, we should reauest the next element from the sink iterator
168+ // before requesting elements from the upstream iterators, we should request the next element from the sink iterator
142169 // if it has some stacked values
143-
144170 // for now we leave it commented as I'm not sure it is not counterproductive.
145171 // This "early" drain might prevent from requesting the next available upstream iterators as soon as possible
146172 // since the sink iterator might deliver a value and the next will return right away
147173
148- // guard await !self.elementCounter.hasElement() else {
149- // return try await self.nextElementFromSink()
150- // }
151-
152- let localSink = self . sink
153- let localElementCounter = self . elementCounter
174+ // guard await !self.elementCounter.hasElement() else {
175+ // return try await self.nextElementFromSink()
176+ // }
154177
155178 // iterating over the upstream iterators to ask for their next element. Only
156- // the available iterators are requested (not already being computing the next
179+ // the available iterators will respond (not already being computing the next
157180 // element from the previous iteration and not already finished)
158- for upstreamIterator in self . upstreamIterators {
159- guard !Task. isCancelled else { break }
160-
161- let localUpstreamIterator = upstreamIterator
162- guard await !localUpstreamIterator. isFinished ( ) else { continue }
181+ for upstreamAsyncSequenceRegulator in self . upstreamAsyncSequenceRegulators {
163182 Task {
164- do {
165- let nextSharedElement = try await localUpstreamIterator. next ( )
166-
167- // if the next element is nil, it means one of the upstream iterator
168- // is finished ... its does not mean the zipped async sequence is finished (all upstream iterators have to be finished)
169- guard let nextNonNilSharedElement = nextSharedElement else {
170- await localSink. send ( . finished)
171- return
172- }
173-
174- guard case let . value( nextElement) = nextNonNilSharedElement else {
175- // the upstream iterator was not available ... see you at the next iteration
176- return
177- }
178-
179- // we have a next element from an upstream iterator, pushing it in the sink stream
180- await localSink. send ( . element( nextElement) )
181- await localElementCounter. increaseCounter ( )
182- } catch is CancellationError {
183- await localSink. send ( . finished)
184- } catch {
185- await localSink. send ( termination: . failure( error) )
186- }
183+ await upstreamAsyncSequenceRegulator. requestNextIfAvailable ( )
187184 }
188185 }
189186
190187 // we wait for the sink iterator to deliver the next element
191- return try await self . nextElementFromSink ( )
188+ return try await self . nextElementFromDownstreamStream ( )
192189 }
193190 }
194191}
0 commit comments