-
Notifications
You must be signed in to change notification settings - Fork 6
/
seqhelper.go
142 lines (131 loc) · 3.98 KB
/
seqhelper.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package go2linq
import (
"context"
"fmt"
"iter"
"slices"
"strings"
"github.com/solsw/errorhelper"
"golang.org/x/sync/errgroup"
)
// VarToSeq returns an iterator over the [variadic] parameter elements.
//
// [variadic]: https://go.dev/ref/spec#Function_types
func VarToSeq[E any](s ...E) iter.Seq[E] {
return slices.Values(s)
}
// StringFmt returns string representation of a sequence:
// - if 'seq' is nil, empty string is returned;
// - if 'T' implements [fmt.Stringer], it is used to convert each element to string;
// - 'sep' separates elements;
// - 'lrim' and 'rrim' surround each element;
// - 'ledge' and 'redge' surround the whole string.
func StringFmt[T any](seq iter.Seq[T], sep, lrim, rrim, ledge, redge string) string {
if seq == nil {
return ""
}
var b strings.Builder
for t := range seq {
if b.Len() > 0 {
b.WriteString(sep)
}
b.WriteString(lrim + fmt.Sprint(t) + rrim)
}
return ledge + b.String() + redge
}
// StringDef returns string representation of a sequence using default formatting.
// If 'seq' is nil, empty string is returned.
func StringDef[T any](seq iter.Seq[T]) string {
if seq == nil {
return ""
}
return StringFmt(seq, " ", "", "", "[", "]")
}
// StringFmt2 returns string representation of a sequence:
// - if 'seq2' is nil, empty string is returned;
// - if 'T' implements [fmt.Stringer], it is used to convert each element to string;
// - 'psep' separates pair of values;
// - 'esep' separates elements;
// - 'lrim' and 'rrim' surround each element;
// - 'ledge' and 'redge' surround the whole string.
func StringFmt2[K, V any](seq2 iter.Seq2[K, V], psep, esep, lrim, rrim, ledge, redge string) string {
if seq2 == nil {
return ""
}
var b strings.Builder
for k, v := range seq2 {
if b.Len() > 0 {
b.WriteString(esep)
}
b.WriteString(lrim + fmt.Sprint(k) + psep + fmt.Sprint(v) + rrim)
}
return ledge + b.String() + redge
}
// StringDef2 returns string representation of a sequence using default formatting.
// If 'seq2' is nil, empty string is returned.
func StringDef2[K, V any](seq2 iter.Seq2[K, V]) string {
if seq2 == nil {
return ""
}
return StringFmt2(seq2, ":", " ", "", "", "[", "]")
}
// ForEach sequentially performs a specified 'action' on each element of the sequence.
// If 'ctx' is canceled or 'action' returns non-nil error,
// operation is stopped and corresponding error is returned.
func ForEach[T any](ctx context.Context, seq iter.Seq[T], action func(T) error) error {
if seq == nil {
return errorhelper.CallerError(ErrNilSource)
}
if action == nil {
return errorhelper.CallerError(ErrNilAction)
}
for t := range seq {
select {
case <-ctx.Done():
return errorhelper.CallerError(ctx.Err())
default:
if err := action(t); err != nil {
return errorhelper.CallerError(err)
}
}
}
return nil
}
// ForEachConcurrent concurrently performs a specified 'action' on each element of the sequence.
// If 'ctx' is canceled or 'action' returns non-nil error,
// operation is stopped and corresponding error is returned.
func ForEachConcurrent[T any](ctx context.Context, seq iter.Seq[T], action func(T) error) error {
if seq == nil {
return errorhelper.CallerError(ErrNilSource)
}
if action == nil {
return errorhelper.CallerError(ErrNilAction)
}
g := new(errgroup.Group)
for t := range seq {
g.Go(func() error {
select {
case <-ctx.Done():
return errorhelper.CallerError(ctx.Err())
default:
if err := action(t); err != nil {
return errorhelper.CallerError(err)
}
}
return nil
})
}
return errorhelper.CallerError(g.Wait())
}
// SeqString converts a sequence to a sequence of strings.
func SeqString[T any](seq iter.Seq[T]) (iter.Seq[string], error) {
return Select(seq, func(t T) string { return fmt.Sprint(t) })
}
// Strings returns a sequence contents as a slice of strings.
func Strings[T any](seq iter.Seq[T]) ([]string, error) {
seqString, err := SeqString(seq)
if err != nil {
return nil, errorhelper.CallerError(err)
}
return slices.Collect(seqString), nil
}