-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmultierr.go
139 lines (125 loc) · 2.42 KB
/
multierr.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
package goutils
import (
"errors"
"strings"
"sync"
)
// MultiErr represent a bucket of errors.
// Usually it should be used as follow:
// var m MultiErr
// for _, id := range []string{"1", "2"} {
// id := id
// go func1() {
// err := somefunc1(id)
// m.Set(id, err)
// }
// }
//
// MultiErr all method is goroutine-safe(lock-guarded).
type MultiErr struct {
mu sync.Mutex
errs map[string]error
}
// Set sets an id with an error.
func (m *MultiErr) Set(id string, err error) {
m.mu.Lock()
if m.errs == nil {
m.errs = map[string]error{}
}
m.errs[id] = err
m.mu.Unlock()
}
// Get gets the id's error. If id not absent, it returns a nil.
func (m *MultiErr) Get(id string) (err error) {
m.mu.Lock()
if m.errs != nil {
err = m.errs[id]
}
m.mu.Unlock()
return
}
// GetE gets the id's error and a bool represent if id exists.
func (m *MultiErr) GetE(id string) (err error, ok bool) { // nolint: revive
m.mu.Lock()
if m.errs != nil {
err, ok = m.errs[id]
}
m.mu.Unlock()
return
}
// All returns true if all id's error is nil.
func (m *MultiErr) All() (all bool) {
m.mu.Lock()
defer m.mu.Unlock()
if m.errs != nil {
for _, v := range m.errs {
if v != nil {
return
}
}
}
all = true
return
}
// Error returns an error. It returns nil if All returns true.
func (m *MultiErr) Error() error {
if m.All() {
return nil
}
return errors.New(m.String())
}
// Range loops errors. It stops loop if `f` returns false.
func (m *MultiErr) Range(f func(id string, err error) bool) {
m.mu.Lock()
for k, v := range m.errs {
if !f(k, v) {
break
}
}
m.mu.Unlock()
}
// String gets description of MultiErr.
func (m *MultiErr) String() string {
m.mu.Lock()
defer m.mu.Unlock()
if m.errs == nil {
return "success"
}
var sb strings.Builder
var notfisrt bool
for id, err := range m.errs {
if err != nil {
if notfisrt {
sb.WriteByte(';')
} else {
notfisrt = true
}
sb.WriteString(id)
sb.WriteByte(':')
sb.WriteString(err.Error())
}
}
return sb.String()
}
// Successes gets successful id list.
func (m *MultiErr) Successes() (ids []string) {
m.mu.Lock()
defer m.mu.Unlock()
for k, v := range m.errs {
if v == nil {
ids = append(ids, k)
}
}
return ids
}
// Fails gets failed id list.
func (m *MultiErr) Fails() (ids []string) {
m.mu.Lock()
defer m.mu.Unlock()
for k, v := range m.errs {
if v != nil {
ids = append(ids, k)
}
}
return ids
}