-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathstruct.go
98 lines (85 loc) · 2.45 KB
/
struct.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
package errors
import "runtime"
// errorInfo holds a description of an error along with information about
// where the error was created.
//
// It may be embedded in custom error types to add
// extra information that this errors package can
// understand.
type errorInfo struct {
// message holds the text of the error message. It may be empty
// if underlying is set.
message string
// cause holds the cause of the error as returned
// by the Cause method.
cause error
// underlying holds the underlying error, if any.
underlying error
// callerPC holds the program counter of the calling
// code that created the error. For some reason, a single
// caller PC is not enough to allow CallersFrames
// to extract a single source location.
callerPC [2]uintptr
}
func newError(underlying, cause error, msg string) error {
err := &errorInfo{
underlying: underlying,
cause: cause,
message: msg,
}
// Skip two frames as we're interested in the caller of the
// caller of newError.
err.setLocation(2)
return err
}
// Underlying returns the underlying error if any.
func (e *errorInfo) Underlying() error {
return e.underlying
}
// Cause implements Causer.
func (e *errorInfo) Cause() error {
return e.cause
}
// Message returns the top level error message.
func (e *errorInfo) Message() string {
return e.message
}
// Error implements error.Error.
func (e *errorInfo) Error() string {
switch {
case e.message == "" && e.underlying == nil:
return "<no error>"
case e.message == "":
return e.underlying.Error()
case e.underlying == nil:
return e.message
}
return e.message + ": " + e.underlying.Error()
}
// GoString returns the details of the receiving error message, so that
// printing an error with %#v will produce useful information.
func (e *errorInfo) GoString() string {
return Details(e)
}
func (e *errorInfo) setLocation(callDepth int) {
// Technically this might not be correct in the future
// because with mid-stack inlining, the skip count
// might not directly correspond to the number of
// frames to skip.
//
// If this fails, we'll leave the location as is,
// which seems reasonable.
var callerPC [2]uintptr
if runtime.Callers(callDepth+2, callerPC[:]) == len(callerPC) {
e.callerPC = callerPC
}
}
// Location implements Locator.
func (e *errorInfo) Location() (file string, line int) {
frames := runtime.CallersFrames(e.callerPC[:])
frame, ok := frames.Next()
if ok {
return frame.File, frame.Line
}
return "", 0
}