@@ -30,6 +30,35 @@ type Iterator interface {
30
30
Close () // ends the iterator
31
31
}
32
32
33
+ // SourceIterator represents a sequence of nodes like [Iterator]
34
+ // Each node also has a named 'source'.
35
+ type SourceIterator interface {
36
+ Iterator
37
+ NodeSource () string // source of current node
38
+ }
39
+
40
+ // WithSource attaches a 'source name' to an iterator.
41
+ func WithSourceName (name string , it Iterator ) SourceIterator {
42
+ return sourceIter {it , name }
43
+ }
44
+
45
+ func ensureSourceIter (it Iterator ) SourceIterator {
46
+ if si , ok := it .(SourceIterator ); ok {
47
+ return si
48
+ }
49
+ return WithSourceName ("" , it )
50
+ }
51
+
52
+ type sourceIter struct {
53
+ Iterator
54
+ name string
55
+ }
56
+
57
+ // NodeSource implements IteratorSource.
58
+ func (it sourceIter ) NodeSource () string {
59
+ return it .name
60
+ }
61
+
33
62
// ReadNodes reads at most n nodes from the given iterator. The return value contains no
34
63
// duplicates and no nil values. To prevent looping indefinitely for small repeating node
35
64
// sequences, this function calls Next at most n times.
@@ -106,16 +135,16 @@ func (it *sliceIter) Close() {
106
135
// Filter wraps an iterator such that Next only returns nodes for which
107
136
// the 'check' function returns true.
108
137
func Filter (it Iterator , check func (* Node ) bool ) Iterator {
109
- return & filterIter {it , check }
138
+ return & filterIter {ensureSourceIter ( it ) , check }
110
139
}
111
140
112
141
type filterIter struct {
113
- Iterator
142
+ SourceIterator
114
143
check func (* Node ) bool
115
144
}
116
145
117
146
func (f * filterIter ) Next () bool {
118
- for f .Iterator .Next () {
147
+ for f .SourceIterator .Next () {
119
148
if f .check (f .Node ()) {
120
149
return true
121
150
}
@@ -135,9 +164,9 @@ func (f *filterIter) Next() bool {
135
164
// It's safe to call AddSource and Close concurrently with Next.
136
165
type FairMix struct {
137
166
wg sync.WaitGroup
138
- fromAny chan * Node
167
+ fromAny chan mixItem
139
168
timeout time.Duration
140
- cur * Node
169
+ cur mixItem
141
170
142
171
mu sync.Mutex
143
172
closed chan struct {}
@@ -146,11 +175,16 @@ type FairMix struct {
146
175
}
147
176
148
177
type mixSource struct {
149
- it Iterator
150
- next chan * Node
178
+ it SourceIterator
179
+ next chan mixItem
151
180
timeout time.Duration
152
181
}
153
182
183
+ type mixItem struct {
184
+ n * Node
185
+ source string
186
+ }
187
+
154
188
// NewFairMix creates a mixer.
155
189
//
156
190
// The timeout specifies how long the mixer will wait for the next fairly-chosen source
@@ -159,7 +193,7 @@ type mixSource struct {
159
193
// timeout makes the mixer completely fair.
160
194
func NewFairMix (timeout time.Duration ) * FairMix {
161
195
m := & FairMix {
162
- fromAny : make (chan * Node ),
196
+ fromAny : make (chan mixItem ),
163
197
closed : make (chan struct {}),
164
198
timeout : timeout ,
165
199
}
@@ -175,7 +209,11 @@ func (m *FairMix) AddSource(it Iterator) {
175
209
return
176
210
}
177
211
m .wg .Add (1 )
178
- source := & mixSource {it , make (chan * Node ), m .timeout }
212
+ source := & mixSource {
213
+ it : ensureSourceIter (it ),
214
+ next : make (chan mixItem ),
215
+ timeout : m .timeout ,
216
+ }
179
217
m .sources = append (m .sources , source )
180
218
go m .runSource (m .closed , source )
181
219
}
@@ -201,7 +239,7 @@ func (m *FairMix) Close() {
201
239
202
240
// Next returns a node from a random source.
203
241
func (m * FairMix ) Next () bool {
204
- m .cur = nil
242
+ m .cur = mixItem {}
205
243
206
244
for {
207
245
source := m .pickSource ()
@@ -217,12 +255,12 @@ func (m *FairMix) Next() bool {
217
255
}
218
256
219
257
select {
220
- case n , ok := <- source .next :
258
+ case item , ok := <- source .next :
221
259
if ok {
222
260
// Here, the timeout is reset to the configured value
223
261
// because the source delivered a node.
224
262
source .timeout = m .timeout
225
- m .cur = n
263
+ m .cur = item
226
264
return true
227
265
}
228
266
// This source has ended.
@@ -239,15 +277,20 @@ func (m *FairMix) Next() bool {
239
277
240
278
// Node returns the current node.
241
279
func (m * FairMix ) Node () * Node {
242
- return m .cur
280
+ return m .cur .n
281
+ }
282
+
283
+ // NodeSource returns the current node's source name.
284
+ func (m * FairMix ) NodeSource () string {
285
+ return m .cur .source
243
286
}
244
287
245
288
// nextFromAny is used when there are no sources or when the 'fair' choice
246
289
// doesn't turn up a node quickly enough.
247
290
func (m * FairMix ) nextFromAny () bool {
248
- n , ok := <- m .fromAny
291
+ item , ok := <- m .fromAny
249
292
if ok {
250
- m .cur = n
293
+ m .cur = item
251
294
}
252
295
return ok
253
296
}
@@ -284,10 +327,10 @@ func (m *FairMix) runSource(closed chan struct{}, s *mixSource) {
284
327
defer m .wg .Done ()
285
328
defer close (s .next )
286
329
for s .it .Next () {
287
- n := s .it .Node ()
330
+ item := mixItem { s .it .Node (), s . it . NodeSource ()}
288
331
select {
289
- case s .next <- n :
290
- case m .fromAny <- n :
332
+ case s .next <- item :
333
+ case m .fromAny <- item :
291
334
case <- closed :
292
335
return
293
336
}
0 commit comments