-
Notifications
You must be signed in to change notification settings - Fork 0
/
list.go
209 lines (178 loc) · 5.82 KB
/
list.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
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
package errm
import (
"sync"
)
// List object is useful for collecting multiple errors into a single error,
// in which error messages are separated by a ";". This object is not safe for concurrent/parallel usage.
type List struct {
errs []error
}
// NewList returns a new [List] instance with an empty underlying slice.
// Working with [List] will cause allocations, use [NewListWithCapacity] if you know the number of errors.
func NewList() *List {
return &List{}
}
// NewListWithCapacity returns a new [List] instance with an initialized underlying slice.
// It may be useful if you know the number of errors and you want to optimize code.
func NewListWithCapacity(capacity int) *List {
return &List{errs: make([]error, 0, capacity)}
}
// Add appends an error to the underlying slice. It is noop if you provide an empty error.
func (e *List) Add(err error) {
if err == nil {
return
}
e.errs = append(e.errs, err)
}
// New creates an error using [New] and appends in to the underlying slice.
func (e *List) New(err string, fields ...any) {
e.errs = append(e.errs, New(err, fields...))
}
// Errorf creates an error using [Errorf] and appends in to the underlying slice.
func (e *List) Errorf(format string, args ...any) {
e.errs = append(e.errs, Errorf(format, args...))
}
// Wrap creates an error using [Wrap] and appends in to the underlying slice.
func (e *List) Wrap(err error, format string, fields ...any) {
e.errs = append(e.errs, Wrap(err, format, fields...))
}
// Wrapf creates an error using [Wrapf] and appends in to the underlying slice.
func (e *List) Wrapf(err error, format string, args ...any) {
e.errs = append(e.errs, Wrapf(err, format, args...))
}
// Has returns true if the [List] contains the given error.
func (e *List) Has(err error, errs ...error) bool {
for _, e := range e.errs {
if Is(e, err) {
return true
}
for _, err2 := range errs {
if Is(e, err2) {
return true
}
}
}
return false
}
// Err returns current [List] instance as error interface or nil if it is empty.
func (e *List) Err() error {
if len(e.errs) == 0 {
return nil
}
return listError{e}
}
// Empty returns true if the [List] collector is empty.
func (e *List) Empty() bool {
return len(e.errs) == 0
}
// NotEmpty returns true if the [List] collector has errors.
func (e *List) NotEmpty() bool {
return len(e.errs) != 0
}
// Clear removes an underlying slice of errors.
func (e *List) Clear() {
e.errs = nil
}
// Len returns the number of errors in [List].
func (e *List) Len() int {
return len(e.errs)
}
// SafeList object is useful for collecting multiple errors from different goroutines into a single error,
// in which error messages are separated by a ";". It is safe for concurrent/parallel usage.
type SafeList struct {
List *List
mu sync.Mutex
}
// NewSafeList returns a new [SafeList] instance with an empty underlying slice.
// Working with [SafeList] will cause allocations, use [NewSafeListWithCapacity] if you know the number of errors.
func NewSafeList() *SafeList {
return &SafeList{
List: NewList(),
}
}
// NewSafeListWithCapacity returns a new [SafeList] instance with an initialized underlying slice.
// It may be useful if you know the number of errors and you want to optimize code.
func NewSafeListWithCapacity(capacity int) *SafeList {
return &SafeList{
List: NewListWithCapacity(capacity),
}
}
// Add appends an error to the underlying slice. It is noop if you provide an empty error.
// It is safe for concurrent/parallel usage.
func (e *SafeList) Add(err error) {
e.mu.Lock()
defer e.mu.Unlock()
e.List.Add(err)
}
// New creates an error using [New] and appends in to the underlying slice.
// It is safe for concurrent/parallel usage.
func (e *SafeList) New(err string, fields ...any) {
e.mu.Lock()
defer e.mu.Unlock()
e.List.New(err, fields...)
}
// Errorf creates an error using [Errorf] and appends in to the underlying slice.
// It is safe for concurrent/parallel usage.
func (e *SafeList) Errorf(format string, args ...any) {
e.mu.Lock()
defer e.mu.Unlock()
e.List.Errorf(format, args...)
}
// Wrap creates an error using [Wrap] and appends in to the underlying slice.
// It is safe for concurrent/parallel usage.
func (e *SafeList) Wrap(err error, format string, fields ...any) {
e.mu.Lock()
defer e.mu.Unlock()
e.List.Wrap(err, format, fields...)
}
// Wrapf creates an error using [Wrapf] and appends in to the underlying slice.
// It is safe for concurrent/parallel usage.
func (e *SafeList) Wrapf(err error, format string, args ...any) {
e.mu.Lock()
defer e.mu.Unlock()
e.List.Wrapf(err, format, args...)
}
// Has returns true if the [SafeList] contains the given error. It is safe for concurrent/parallel usage.
func (e *SafeList) Has(err error) bool {
e.mu.Lock()
defer e.mu.Unlock()
return e.List.Has(err)
}
// Empty return true if the [SafeList] collector is empty. It is safe for concurrent/parallel usage.
func (e *SafeList) Empty() bool {
e.mu.Lock()
defer e.mu.Unlock()
return e.List.Empty()
}
// NotEmpty return true if the [SafeList] collector has errors. It is safe for concurrent/parallel usage.
func (e *SafeList) NotEmpty() bool {
e.mu.Lock()
defer e.mu.Unlock()
return e.List.NotEmpty()
}
// Err returns current [SafeList] instance as error interface or nil if it is empty.
// It is safe for concurrent/parallel usage.
func (e *SafeList) Err() error {
e.mu.Lock()
defer e.mu.Unlock()
return e.List.Err()
}
// Clear removes underlying slice of errors. It is safe for concurrent/parallel usage.
func (e *SafeList) Clear() {
e.mu.Lock()
defer e.mu.Unlock()
e.List.Clear()
}
// Len returns the number of errors in [SafeList]. It is safe for concurrent/parallel usage.
func (e *SafeList) Len() int {
e.mu.Lock()
defer e.mu.Unlock()
return e.List.Len()
}
type listError struct{ *List }
func (e listError) Error() string {
if len(e.errs) == 0 {
return ""
}
return JoinErrors(e.errs...).Error()
}