-
Notifications
You must be signed in to change notification settings - Fork 0
/
aerrors.go
181 lines (154 loc) · 3.14 KB
/
aerrors.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
package aerrors
import (
"errors"
"reflect"
"sync"
)
var errorPool = &sync.Pool{
New: func() interface{} {
return &AError{
buf: make([]byte, 0, 500),
}
},
}
func newAError(code Code, reason string) *AError {
e := errorPool.Get().(*AError)
e.buf = e.buf[:0]
e.withCode(code).withReason(reason)
return e
}
func putEvent(e *AError) {
errorPool.Put(e)
}
type TypeCoder interface {
TypeCode() string
}
type Code string
func (err Code) TypeCode() string {
if err == ErrOK {
return ""
}
return string(err)
}
func (err Code) Error() string {
if err == ErrOK {
return ""
}
return string(err)
}
type Error interface {
Error() string
}
type Builder interface {
WithParent(parent error) Builder
WithMessage(message string) Builder
WithStack() Builder
Err() Error
withCode(code Code) Builder
withReason(reason string) Builder
}
type AError struct {
parent error
code Code
reason string
message string
stack string
buf []byte
}
func New(code Code, reason string) Builder {
return newAError(code, reason)
}
func (err *AError) WithParent(parent error) Builder {
if err == nil {
return nil
}
err.parent = parent
err.buf = err.appendString(err.appendKey(err.buf, "parent"), parent.Error())
return err
}
func (err *AError) WithMessage(message string) Builder {
if err == nil {
return nil
}
err.message = message
err.buf = err.appendString(err.appendKey(err.buf, "message"), message)
return err
}
func (err *AError) WithStack() Builder {
if err == nil {
return nil
}
const depth = 32
err.stack = LogStack(2, depth)
return err
}
func (err *AError) Err() Error {
if err == nil {
return nil
}
err.buf = err.appendString(err.appendLineBreak(err.buf), err.stack)
putEvent(err)
return err
}
// nolint
func (err AError) Error() string {
return BytesToString(err.buf)
}
func (err *AError) Is(target error) bool {
t, ok := target.(*AError)
if !ok {
return false
}
if t.code != ErrOK && t.code != err.code {
return false
}
if t.reason != "" && t.reason != err.reason {
return false
}
if t.parent != nil && !errors.Is(err.parent, t.parent) {
return false
}
return true
}
func (err *AError) As(target interface{}) bool {
_, ok := target.(**AError)
if !ok {
return false
}
reflect.Indirect(reflect.ValueOf(target)).Set(reflect.ValueOf(err))
return true
}
func (err *AError) withCode(code Code) Builder {
err.code = code
err.buf = err.appendString(err.appendKey(err.buf, "code"), code.Error())
return err
}
func (err *AError) withReason(reason string) Builder {
err.reason = reason
err.buf = err.appendString(err.appendKey(err.buf, "reason"), reason)
return err
}
func TypeCode(err error) string {
if err == nil {
return ErrOK.TypeCode()
}
var e TypeCoder
if errors.As(err, &e) {
return e.TypeCode()
}
return ErrUnknown.TypeCode()
}
func (err *AError) appendKey(dst []byte, key string) []byte {
if (len(dst)) != 0 {
dst = append(dst, ',')
}
return append(err.appendString(dst, key), ':')
}
func (err *AError) appendString(dst []byte, s string) []byte {
b := StringToBytes(s)
dst = append(dst, b...)
return dst
}
func (err *AError) appendLineBreak(dst []byte) []byte {
return append(dst, '\n')
}