-
Notifications
You must be signed in to change notification settings - Fork 0
/
shared_error.go
153 lines (122 loc) · 2.73 KB
/
shared_error.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
/**
* Copyright (c) 2021, Xerra Earth Observation Institute
* All rights reserved. Use is subject to License terms.
* See LICENSE.TXT in the root directory of this source tree.
*/
package sharederror
import (
"errors"
"fmt"
"sync"
)
// SharedError implements goroutine-safe error handling.
// Multiple concurrent goroutines can share a SharedError variable to reports errors
// to the calling function.
type SharedError struct {
err []error
lock sync.Mutex
}
// NewSharedError creates new shared-error.
func NewSharedError() *SharedError {
return &SharedError{}
}
// Error implements the error interface, you can return a SharedError as an error.
func (s *SharedError) Error() string {
s.lock.Lock()
defer s.lock.Unlock()
return s.string()
}
// assumes that s is already locked
func (s *SharedError) string() string {
if len(s.err) == 0 {
return ""
}
if len(s.err) == 1 {
return s.err[0].Error()
}
errorStr := ""
for i, err := range s.err {
if i != 0 {
errorStr += " / "
}
errorStr += fmt.Sprintf("error %d: %v", i, err)
}
return errorStr
}
// Triggered returns true if an error is stored in the ShareError, or false for no error.
func (s *SharedError) Triggered() bool {
s.lock.Lock()
defer s.lock.Unlock()
if len(s.err) == 0 {
return false
}
return true
}
// Store stores an error condition in SharedError.
func (s *SharedError) Store(err error) {
if err == nil {
return
}
s.lock.Lock()
defer s.lock.Unlock()
s.err = append(s.err, err)
}
// Return any error and reset the error if it was triggered.
func (s *SharedError) Reset() error {
if s == nil {
return nil
}
s.lock.Lock()
defer s.lock.Unlock()
err := s.string()
s.err = nil
if err == "" {
return nil
}
return errors.New(err)
}
// Store stores an error condition in SharedError.
func (s *SharedError) Storef(format string, args ...interface{}) {
if format == "" {
return
}
s.lock.Lock()
defer s.lock.Unlock()
s.err = append(s.err, fmt.Errorf(format, args...))
}
// Err returns SharedError as an error when triggered.
func (s *SharedError) Err() error {
if s.Triggered() {
return s
} else {
return nil
}
}
// Errors returns SharedError errors if any.
func (s *SharedError) Errors() []error {
s.lock.Lock()
defer s.lock.Unlock()
return s.err
}
// IsAny checks if any error of SharedError matches target error.
func (s *SharedError) IsAny(target error) bool {
for _, err := range s.Errors() {
if errors.Is(err, target) {
return true
}
}
return false
}
// IsAny checks if all errors of SharedError matches target error.
func (s *SharedError) IsAll(target error) bool {
errs := s.Errors()
if len(errs) == 0 {
return false
}
for _, err := range errs {
if !errors.Is(err, target) {
return false
}
}
return true
}