-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathfactory.go
164 lines (131 loc) · 4.37 KB
/
factory.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
package gerror
import (
"strings"
)
// The Factory interface exposes only methods that can be used for cloning an error.
// But all errors implement this by default.
// This allows for dynamic and mutable errors without modifying the base.
type Factory interface {
// Base clones the error without modifications.
Base() Error
// SourceOnly clones the error and ensures Source is populated.
SourceOnly() Error
// Stack clones the error and ensures there is a Stack. Source will also be populated
// if not already set.
Stack() Error
// Src clones the error with a custom source.
Src(src string) Error
// DTag clones the error with a detailTag, and will populate Source if needed.
DTag(dTag string) Error
// Msg clones the error, extends its message, and will populate a Source if needed.
Msg(fmt string, elems ...any) Error
// DTagSrcMsg clones the error, adds a Detail tag, custom source, and extends its message.
SrcDTagMsg(src, dTag, fmt string, elems ...any) Error
// SrcDTag clones the error, adds a detail tag and source.
SrcDTag(src, dTag string) Error
// SrcMsg clones the error, adds a source, and extends its message.
SrcMsg(src, fmt string, elems ...any) Error
// DTagSrc clones the error, adds a detail tag, and extends its message.
DTagMsg(dTag, fmt string, elems ...any) Error
// SrcS is the same as Src but also includes a full StackTrace.
SrcS(src string) Error
// DTagS is the same as DTag but also includes a full StackTrace.
DTagS(dTag string) Error
// MsgS is the same as Msg but also includes a full StackTrace.
MsgS(fmt string, elems ...any) Error
// SrcDTagMsgS is the same as DTagSrcMsg but also includes a full StackTrace.
SrcDTagMsgS(src, dTag, fmt string, elems ...any) Error
// SrcDTagS is the same as DTagSrc but also includes a full StackTrace.
SrcDTagS(src, dTag string) Error
// SrcMsgS is the same as SrcMsg but also includes a full StackTrace.
SrcMsgS(src, fmt string, elems ...any) Error
// DTagSrcS is the same as DTagMsg but also includes a full StackTrace.
DTagMsgS(dTag, fmt string, elems ...any) Error
// Convert will attempt to convert the supplied error into a gError.Error of the
// Factory's type, including the source errors details in the result's error message.
// The original error's equality can be checked with errors.Is().
Convert(err error) Error
// ConvertS is the same as Convert but includes a full StackTrace.
ConvertS(err error) Error
// Error implements the standard Error interface so that a Factory
// can be passed into errors.Is() as a target.
Error() string
// Is implements the interface for error matching in the standard package (errors.IS).
Is(error) bool
}
type factoryOf interface {
Error
Factory
}
// FactoryOf returns a factory instance of this error.
func FactoryOf[T factoryOf](err T) Factory {
err._embededGError().isFactory = true
return err
}
// CloneBase is used by factory methods.
func CloneBase[T factoryOf](
err T,
stackType StackType,
dTag string,
source string,
extMsg string, // PRE FORMATED!
srcError error, // Be careful with this...
) *GError {
base := err._embededGError()
fRef := factoryOf(base)
if base.factoryRef != nil {
fRef = base.factoryRef
}
clone := &GError{
Name: base.Name,
Message: base.Message,
Source: base.Source,
detailTag: base.detailTag,
factoryRef: fRef,
stack: base.stack,
srcError: base.srcError,
}
// handle source:
if source != "" && clone.Source == "" {
clone.Source = source
}
// handle detail tags:
if dTag != "" {
if clone.detailTag == "" {
clone.detailTag = dTag
} else {
clone.detailTag += "-" + dTag
}
}
// handle message extension:
extMsg = strings.TrimSpace(extMsg)
if extMsg != "" {
if clone.Message == "" {
clone.Message = extMsg
} else {
clone.Message += " " + extMsg
}
}
// handle error inheritance:
if clone.factoryRef == nil && base.isFactory {
clone.factoryRef = err
}
if clone.srcError == nil && srcError != nil {
clone.srcError = srcError
}
// If we already have a stack, don't want one, or want a source and already have it
// skip stacks.
if len(clone.stack) > 0 ||
stackType == NoStack ||
stackType == SourceStack && clone.Source != "" {
return clone
}
clone.stack = makeStack(stackType, defaultSkip)
if clone.Source == "" {
clone.Source = clone.stack.NearestExternal().Metric()
if stackType == SourceStack {
clone.stack = nil
}
}
return clone
}