@@ -21,29 +21,29 @@ var (
21
21
22
22
type (
23
23
// ForEachFunc is used to do element processing, but no output.
24
- ForEachFunc func (item interface {} )
24
+ ForEachFunc [ T any ] func (item T )
25
25
// GenerateFunc is used to let callers send elements into source.
26
- GenerateFunc func (source chan <- interface {} )
26
+ GenerateFunc [ T any ] func (source chan <- T )
27
27
// MapFunc is used to do element processing and write the output to writer.
28
- MapFunc func (item interface {} , writer Writer )
28
+ MapFunc [ T , U any ] func (item T , writer Writer [ U ] )
29
29
// MapperFunc is used to do element processing and write the output to writer,
30
30
// use cancel func to cancel the processing.
31
- MapperFunc func (item interface {} , writer Writer , cancel func (error ))
31
+ MapperFunc [ T , U any ] func (item T , writer Writer [ U ] , cancel func (error ))
32
32
// ReducerFunc is used to reduce all the mapping output and write to writer,
33
33
// use cancel func to cancel the processing.
34
- ReducerFunc func (pipe <- chan interface {} , writer Writer , cancel func (error ))
34
+ ReducerFunc [ U , V any ] func (pipe <- chan U , writer Writer [ V ] , cancel func (error ))
35
35
// VoidReducerFunc is used to reduce all the mapping output, but no output.
36
36
// Use cancel func to cancel the processing.
37
- VoidReducerFunc func (pipe <- chan interface {} , cancel func (error ))
37
+ VoidReducerFunc [ U any ] func (pipe <- chan U , cancel func (error ))
38
38
// Option defines the method to customize the mapreduce.
39
39
Option func (opts * mapReduceOptions )
40
40
41
- mapperContext struct {
41
+ mapperContext [ T , U any ] struct {
42
42
ctx context.Context
43
- mapper MapFunc
44
- source <- chan interface {}
43
+ mapper MapFunc [ T , U ]
44
+ source <- chan T
45
45
panicChan * onceChan
46
- collector chan <- interface {}
46
+ collector chan <- U
47
47
doneChan <- chan struct {}
48
48
workers int
49
49
}
54
54
}
55
55
56
56
// Writer interface wraps Write method.
57
- Writer interface {
58
- Write (v interface {} )
57
+ Writer [ T any ] interface {
58
+ Write (v T )
59
59
}
60
60
)
61
61
@@ -65,16 +65,15 @@ func Finish(fns ...func() error) error {
65
65
return nil
66
66
}
67
67
68
- return MapReduceVoid (func (source chan <- interface {} ) {
68
+ return MapReduceVoid (func (source chan <- func () error ) {
69
69
for _ , fn := range fns {
70
70
source <- fn
71
71
}
72
- }, func (item interface {}, writer Writer , cancel func (error )) {
73
- fn := item .(func () error )
72
+ }, func (fn func () error , writer Writer [any ], cancel func (error )) {
74
73
if err := fn (); err != nil {
75
74
cancel (err )
76
75
}
77
- }, func (pipe <- chan interface {} , cancel func (error )) {
76
+ }, func (pipe <- chan any , cancel func (error )) {
78
77
}, WithWorkers (len (fns )))
79
78
}
80
79
@@ -84,27 +83,26 @@ func FinishVoid(fns ...func()) {
84
83
return
85
84
}
86
85
87
- ForEach (func (source chan <- interface {} ) {
86
+ ForEach (func (source chan <- func () ) {
88
87
for _ , fn := range fns {
89
88
source <- fn
90
89
}
91
- }, func (item interface {}) {
92
- fn := item .(func ())
90
+ }, func (fn func ()) {
93
91
fn ()
94
92
}, WithWorkers (len (fns )))
95
93
}
96
94
97
95
// ForEach maps all elements from given generate but no output.
98
- func ForEach (generate GenerateFunc , mapper ForEachFunc , opts ... Option ) {
96
+ func ForEach [ T any ] (generate GenerateFunc [ T ] , mapper ForEachFunc [ T ] , opts ... Option ) {
99
97
options := buildOptions (opts ... )
100
- panicChan := & onceChan {channel : make (chan interface {} )}
98
+ panicChan := & onceChan {channel : make (chan any )}
101
99
source := buildSource (generate , panicChan )
102
- collector := make (chan interface {} , options .workers )
100
+ collector := make (chan any , options .workers )
103
101
done := make (chan struct {})
104
102
105
- go executeMappers (mapperContext {
103
+ go executeMappers (mapperContext [ T , any ] {
106
104
ctx : options .ctx ,
107
- mapper : func (item interface {} , writer Writer ) {
105
+ mapper : func (item T , writer Writer [ any ] ) {
108
106
mapper (item )
109
107
},
110
108
source : source ,
@@ -128,26 +126,26 @@ func ForEach(generate GenerateFunc, mapper ForEachFunc, opts ...Option) {
128
126
129
127
// MapReduce maps all elements generated from given generate func,
130
128
// and reduces the output elements with given reducer.
131
- func MapReduce (generate GenerateFunc , mapper MapperFunc , reducer ReducerFunc ,
132
- opts ... Option ) (interface {} , error ) {
133
- panicChan := & onceChan {channel : make (chan interface {} )}
129
+ func MapReduce [ T , U , V any ] (generate GenerateFunc [ T ] , mapper MapperFunc [ T , U ], reducer ReducerFunc [ U , V ] ,
130
+ opts ... Option ) (V , error ) {
131
+ panicChan := & onceChan {channel : make (chan any )}
134
132
source := buildSource (generate , panicChan )
135
133
return mapReduceWithPanicChan (source , panicChan , mapper , reducer , opts ... )
136
134
}
137
135
138
136
// MapReduceChan maps all elements from source, and reduce the output elements with given reducer.
139
- func MapReduceChan (source <- chan interface {} , mapper MapperFunc , reducer ReducerFunc ,
140
- opts ... Option ) (interface {} , error ) {
141
- panicChan := & onceChan {channel : make (chan interface {} )}
137
+ func MapReduceChan [ T , U , V any ] (source <- chan T , mapper MapperFunc [ T , U ], reducer ReducerFunc [ U , V ] ,
138
+ opts ... Option ) (V , error ) {
139
+ panicChan := & onceChan {channel : make (chan any )}
142
140
return mapReduceWithPanicChan (source , panicChan , mapper , reducer , opts ... )
143
141
}
144
142
145
143
// MapReduceChan maps all elements from source, and reduce the output elements with given reducer.
146
- func mapReduceWithPanicChan (source <- chan interface {} , panicChan * onceChan , mapper MapperFunc ,
147
- reducer ReducerFunc , opts ... Option ) (interface {}, error ) {
144
+ func mapReduceWithPanicChan [ T , U , V any ] (source <- chan T , panicChan * onceChan , mapper MapperFunc [ T , U ] ,
145
+ reducer ReducerFunc [ U , V ], opts ... Option ) (val V , err error ) {
148
146
options := buildOptions (opts ... )
149
147
// output is used to write the final result
150
- output := make (chan interface {} )
148
+ output := make (chan V )
151
149
defer func () {
152
150
// reducer can only write once, if more, panic
153
151
for range output {
@@ -156,7 +154,7 @@ func mapReduceWithPanicChan(source <-chan interface{}, panicChan *onceChan, mapp
156
154
}()
157
155
158
156
// collector is used to collect data from mapper, and consume in reducer
159
- collector := make (chan interface {} , options .workers )
157
+ collector := make (chan U , options .workers )
160
158
// if done is closed, all mappers and reducer should stop processing
161
159
done := make (chan struct {})
162
160
writer := newGuardedWriter (options .ctx , output , done )
@@ -192,9 +190,9 @@ func mapReduceWithPanicChan(source <-chan interface{}, panicChan *onceChan, mapp
192
190
reducer (collector , writer , cancel )
193
191
}()
194
192
195
- go executeMappers (mapperContext {
193
+ go executeMappers (mapperContext [ T , U ] {
196
194
ctx : options .ctx ,
197
- mapper : func (item interface {} , w Writer ) {
195
+ mapper : func (item T , w Writer [ U ] ) {
198
196
mapper (item , w , cancel )
199
197
},
200
198
source : source ,
@@ -207,24 +205,27 @@ func mapReduceWithPanicChan(source <-chan interface{}, panicChan *onceChan, mapp
207
205
select {
208
206
case <- options .ctx .Done ():
209
207
cancel (context .DeadlineExceeded )
210
- return nil , context .DeadlineExceeded
208
+ err = context .DeadlineExceeded
211
209
case v := <- panicChan .channel :
212
210
panic (v )
213
211
case v , ok := <- output :
214
- if err := retErr .Load (); err != nil {
215
- return nil , err .(error )
212
+ if e := retErr .Load (); e != nil {
213
+ err = e .(error )
216
214
} else if ok {
217
- return v , nil
215
+ val = v
218
216
} else {
219
- return nil , ErrReduceNoOutput
217
+ err = ErrReduceNoOutput
220
218
}
221
219
}
220
+
221
+ return
222
222
}
223
223
224
224
// MapReduceVoid maps all elements generated from given generate,
225
225
// and reduce the output elements with given reducer.
226
- func MapReduceVoid (generate GenerateFunc , mapper MapperFunc , reducer VoidReducerFunc , opts ... Option ) error {
227
- _ , err := MapReduce (generate , mapper , func (input <- chan interface {}, writer Writer , cancel func (error )) {
226
+ func MapReduceVoid [T , U any ](generate GenerateFunc [T ], mapper MapperFunc [T , U ],
227
+ reducer VoidReducerFunc [U ], opts ... Option ) error {
228
+ _ , err := MapReduce (generate , mapper , func (input <- chan U , writer Writer [any ], cancel func (error )) {
228
229
reducer (input , cancel )
229
230
}, opts ... )
230
231
if errors .Is (err , ErrReduceNoOutput ) {
@@ -261,8 +262,8 @@ func buildOptions(opts ...Option) *mapReduceOptions {
261
262
return options
262
263
}
263
264
264
- func buildSource (generate GenerateFunc , panicChan * onceChan ) chan interface {} {
265
- source := make (chan interface {} )
265
+ func buildSource [ T any ] (generate GenerateFunc [ T ] , panicChan * onceChan ) chan T {
266
+ source := make (chan T )
266
267
go func () {
267
268
defer func () {
268
269
if r := recover (); r != nil {
@@ -278,13 +279,13 @@ func buildSource(generate GenerateFunc, panicChan *onceChan) chan interface{} {
278
279
}
279
280
280
281
// drain drains the channel.
281
- func drain (channel <- chan interface {} ) {
282
+ func drain [ T any ] (channel <- chan T ) {
282
283
// drain the channel
283
284
for range channel {
284
285
}
285
286
}
286
287
287
- func executeMappers (mCtx mapperContext ) {
288
+ func executeMappers [ T , U any ] (mCtx mapperContext [ T , U ] ) {
288
289
var wg sync.WaitGroup
289
290
defer func () {
290
291
wg .Wait ()
@@ -341,22 +342,21 @@ func once(fn func(error)) func(error) {
341
342
}
342
343
}
343
344
344
- type guardedWriter struct {
345
+ type guardedWriter [ T any ] struct {
345
346
ctx context.Context
346
- channel chan <- interface {}
347
+ channel chan <- T
347
348
done <- chan struct {}
348
349
}
349
350
350
- func newGuardedWriter (ctx context.Context , channel chan <- interface {},
351
- done <- chan struct {}) guardedWriter {
352
- return guardedWriter {
351
+ func newGuardedWriter [T any ](ctx context.Context , channel chan <- T , done <- chan struct {}) guardedWriter [T ] {
352
+ return guardedWriter [T ]{
353
353
ctx : ctx ,
354
354
channel : channel ,
355
355
done : done ,
356
356
}
357
357
}
358
358
359
- func (gw guardedWriter ) Write (v interface {} ) {
359
+ func (gw guardedWriter [ T ] ) Write (v T ) {
360
360
select {
361
361
case <- gw .ctx .Done ():
362
362
return
@@ -368,11 +368,11 @@ func (gw guardedWriter) Write(v interface{}) {
368
368
}
369
369
370
370
type onceChan struct {
371
- channel chan interface {}
371
+ channel chan any
372
372
wrote int32
373
373
}
374
374
375
- func (oc * onceChan ) write (val interface {} ) {
375
+ func (oc * onceChan ) write (val any ) {
376
376
if atomic .AddInt32 (& oc .wrote , 1 ) > 1 {
377
377
return
378
378
}
0 commit comments