-
Notifications
You must be signed in to change notification settings - Fork 0
/
lib.go
191 lines (171 loc) · 4.15 KB
/
lib.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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
package libprisma
import "io"
// Result is a generic type that can hold a value of type T or an error
type Result[T any] struct {
value T
err error
}
func Ok[T any](v T) Result[T] {
return Result[T]{value: v, err: nil}
}
func Err[T any](err error) Result[T] {
return Result[T]{err: err}
}
// May wraps a call to some function that returns value or err and creates a result
func May[T any](v T, err error) Result[T] {
if err != nil {
return Err[T](err)
} else {
return Ok(v)
}
}
// ValueOrPanic returns T if there is no error, otherwise panics
func (r Result[T]) ValueOrPanic() T {
if r.err != nil {
panic(r.err)
}
return r.value
}
// Unwrap returns the value and error of the Result in the usual Go way
func (r Result[T]) Unwrap() (T, error) {
return r.value, r.err
}
// IsErr returns true if the Result has an error
func (r Result[T]) IsErr() bool {
return r.err != nil
}
// ValueOr returns the value if there is no error, otherwise returns the default value
func (r Result[T]) ValueOr(def T) T {
if r.err != nil {
return def
}
return r.value
}
// ValueOrFunc returns the value if there is no error, otherwise returns the result of the function `f`
func (r Result[T]) ValueOrFunc(f func() T) T {
if r.err != nil {
return f()
}
return r.value
}
// Map takes a slice of T and a function that returns a Result[T] applies `f` to `s` and returns a slice of Result[T]
func Map[S ~[]T, T any](s S, f func(T) Result[T]) []Result[T] {
r := make([]Result[T], len(s))
for i, vals := range s {
r[i] = f(vals)
}
return r
}
// Collect takes a slice of Result[T] and returns a slice of T or the first error encountered
func Collect[S ~[]Result[T], T any](s S) ([]T, error) {
r := make([]T, len(s))
for i, val := range s {
if val.err != nil {
return []T{}, val.err
}
r[i] = val.value
}
return r, nil
}
// Switch takes a slice of T and a function that returns a bool,
// it will apply `f` to each T in `s` and will switch T into one of two slices based on the result of `f`
func Switch[S ~[]T, T any](s S, f func(T) bool) ([]T, []T) {
var t []T
var e []T
for _, val := range s {
if f(val) {
t = append(t, val)
} else {
e = append(e, val)
}
}
return t, e
}
// StreamingSwitch takes a channel of T and two channels of T and a function that returns a bool,
// it will apply `f` to each T in `s` and will switch each T from `s` into one of two channels based on the result of `f`
// until `s` is closed
func StreamingSwitch[T any](s chan T, sinkA chan T, sinkB chan T, f func(T) bool) {
defer close(sinkA)
defer close(sinkB)
for {
select {
case val, ok := <-s:
if !ok {
return
}
if f(val) {
sinkA <- val
} else {
sinkB <- val
}
}
}
}
// Stream takes many slices of T and emits each element in the slices in order on the channel `ch`, closing the channel when done
func Stream[S ~[]T, T any](ch chan T, s ...S) {
defer close(ch)
for _, vals := range s {
for _, val := range vals {
ch <- val
}
}
}
type StreamedChunk struct {
Chunk []byte
Read int
Done bool
Err error
}
func StreamReader(ch chan *StreamedChunk, r io.Reader, chunkSize int) {
defer close(ch)
buf := make([]byte, chunkSize)
for {
n, err := r.Read(buf)
if n > 0 {
ch <- &StreamedChunk{
Chunk: buf[:n],
Read: n,
Err: err,
}
}
if n == 0 || err == io.EOF {
ch <- &StreamedChunk{
Chunk: nil,
Read: 0,
Done: true,
Err: err,
}
return
}
if err != nil {
ch <- &StreamedChunk{
Chunk: nil,
Read: 0,
Err: err,
}
return
}
}
}
// Sieve takes a slice of Result[T] and returns a slice of T with the errors removed and a slice of errors if any
func Sieve[S ~[]Result[T], T any](s S) ([]T, []error) {
var vals []T
var errs []error
for _, val := range s {
if val.err != nil {
errs = append(errs, val.err)
continue
}
vals = append(vals, val.value)
}
return vals, errs
}
// MapValToKey takes a map with keys of type K and values of type V, and returns a new map
// with keys and values swapped. The values in the original map should be comparable.
func MapValToKey[K comparable, V comparable](m map[K]V) map[V]K {
r := map[V]K{}
for k, v := range m {
r[v] = k
}
return r
}