-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmultierr.go
130 lines (110 loc) · 2.53 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
// Package multierr is a Go package for aggregating multiple errors into
// a single error.
package multierr
import (
"fmt"
"io"
"reflect"
"slices"
"strings"
"github.com/jordanhasgul/multierr/prefix"
)
// Error is an error type that is used to aggregate multiple errors into
// a single error.
type Error struct {
errs []error
}
// New returns a new Error that contains errs. Any nil errors contained
// within errs are removed.
func New(errs ...error) *Error {
errs = removeNilErrors(errs)
return &Error{errs: errs}
}
// Append returns an Error by appending errs onto err.
//
// If err is not an Error then it will be turned into one. Any nil errors
// contained within errs are removed.
func Append(err error, errs ...error) *Error {
errs = removeNilErrors(errs)
switch err := err.(type) {
case *Error:
if err == nil {
return New(errs...)
}
err.errs = append(err.errs, errs...)
return err
default:
if err == nil {
return New(errs...)
}
errs = append(errs, nil)
copy(errs[1:], errs)
errs[0] = err
return New(errs...)
}
}
func removeNilErrors(errs []error) []error {
del := func(err error) bool {
if err == nil {
return true
}
var (
value = reflect.ValueOf(err)
kind = value.Kind()
nillable = kind == reflect.Ptr || kind == reflect.UnsafePointer ||
kind == reflect.Func || kind == reflect.Map || kind == reflect.Slice ||
kind == reflect.Chan || kind == reflect.Interface
)
return nillable && value.IsNil()
}
return slices.DeleteFunc(errs, del)
}
// Error returns the string representation of an Error.
func (e *Error) Error() string {
if e == nil {
return ""
}
if len(e.errs) == 0 {
return ""
}
var sb strings.Builder
fprintError(&sb, &sb, e)
return sb.String()
}
func fprintError(currWriter, prevWriter io.Writer, e *Error) {
fmt.Fprintf(prevWriter, "%d error(s) occurred:\n", len(e.errs))
for i, err := range e.errs {
var (
pipe = "├── "
sep = "│ "
)
if i == len(e.errs)-1 {
pipe = "└── "
sep = " "
}
switch err := err.(type) {
case *Error:
var (
prevWriter = prefix.New(currWriter, pipe)
currWriter = prefix.New(currWriter, sep)
)
fprintError(currWriter, prevWriter, err)
default:
fmt.Fprintf(currWriter, "%s%s\n", pipe, err)
}
}
}
// Unwrap returns the list of errors that this Error wraps.
func (e *Error) Unwrap() []error {
if e == nil {
return nil
}
return e.errs
}
// Len returns the number of errors that this Error wraps.
func (e *Error) Len() int {
if e == nil {
return 0
}
return len(e.errs)
}