-
Notifications
You must be signed in to change notification settings - Fork 0
/
operations.go
142 lines (124 loc) · 2.79 KB
/
operations.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 iterator
// Pipe applies the modifiers to the given iterator and returns the resulting
// iterator
func Pipe[T any](iter Iterator[T], mods ...Modifier[T, T]) Iterator[T] {
for i := range mods {
iter = mods[i](iter)
}
return iter
}
func Iterate[T any](iterator Iterator[T], f func(int, T) (bool, error)) (int, error) {
var count int
shouldContinue := true
for shouldContinue && iterator.Next() {
r, err := iterator.Get()
if err != nil {
return count, err
}
shouldContinue, err = f(count, r)
if err != nil {
return count, err
}
count++
}
if err := iterator.Err(); err != nil {
return count, err
}
if err := iterator.Close(); err != nil {
return count, err
}
return count, nil
}
// Len exhausts the iterator to return its length
func Len[T any](iter Iterator[T]) (int, error) {
var count int
for iter.Next() {
count++
}
return count, iter.Err()
}
// Equal reports whether the given iterators are equal
func Equal[T comparable](iters ...Iterator[T]) (bool, error) {
for {
var firstHasNext bool
var firstItem T
for i := range iters {
if i == 0 {
firstHasNext = iters[i].Next()
if !firstHasNext {
if err := iters[i].Err(); err != nil {
return false, err
}
}
var err error
firstItem, err = iters[i].Get()
if err != nil {
return false, err
}
} else {
if iters[i].Next() != firstHasNext {
if firstHasNext {
return false, iters[i].Err()
}
return false, nil
}
item, err := iters[i].Get()
if err != nil {
return false, err
}
if item != firstItem {
return false, nil
}
}
}
if !firstHasNext {
var err error
for i := range iters {
if closeErr := iters[i].Close(); err == nil && closeErr != nil {
err = closeErr
}
}
if err != nil {
return false, err
}
return true, nil
}
}
}
// One returns the only item of an iterator.
// If the iterator has no items then it returns ErrNoItems,
// and if the iterator has more than one item then it returns ErrMultiItems.
func One[T any](iterator Iterator[T]) (T, error) {
defer iterator.Close()
var t T
var err error
if iterator.Next() {
t, err = iterator.Get()
if err != nil {
return *new(T), err
}
if iterator.Next() {
return *new(T), ErrMultiItems
}
} else {
return *new(T), ErrNoItems
}
if err := iterator.Err(); err != nil {
return *new(T), err
}
if err := iterator.Close(); err != nil {
return *new(T), err
}
return t, nil
}
// Async calls fn with the given iterator in a separate goroutine
// and returns the result in a ValErr channel.
func Async[T any, V any](iterator Iterator[T], fn func(Iterator[T]) (V, error)) <-chan ValErr[V] {
c := make(chan ValErr[V])
go func() {
v, err := fn(iterator)
c <- ValErr[V]{Val: v, Err: err}
close(c)
}()
return c
}