-
Notifications
You must be signed in to change notification settings - Fork 0
/
unwrap.go
55 lines (45 loc) · 1.4 KB
/
unwrap.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
package multierr
import "errors"
// Unwrap returns the first error in Error or nil if there are no errors.
// By repeatedly calling Unwrap on the return value (until nil is returned),
// all (recursively) contained sub-errors can be obtained.
// Errors are unwrapped depth-first.
// This implements errors.Is/errors.As/errors.Unwrap methods from the standard library.
// Appending new errors while unwrapping has no effect (shallow copy).
func (e *Error) Unwrap() error {
if e == nil || len(e.Errors) == 0 {
return nil
}
if len(e.Errors) == 1 {
return e.Errors[0]
}
// copy, to be independent if new errors are appended/merged while unwrapping
errs := make([]error, len(e.Errors))
copy(errs, e.Errors)
return chain(errs)
}
type chain []error
// Unwrap returns the next error or nil if there are no errors left.
func (e chain) Unwrap() error {
if len(e) == 1 {
// current element is the last one, nothing to unwrap
return nil
}
if err, ok := e[1].(*Error); ok {
// multi-error -> depth-first search
return chain(append(err.Errors, e[2:]...))
}
return e[1:] // remove first (=current) element
}
// Error implements the error interface
func (e chain) Error() string {
return e[0].Error()
}
// Is implements errors.Is.
func (e chain) Is(target error) bool {
return errors.Is(e[0], target)
}
// As implements errors.As.
func (e chain) As(target interface{}) bool {
return errors.As(e[0], target)
}