File: struct.go

package info (click to toggle)
golang-gopkg-errgo.v2 2.1.0-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, forky, sid, trixie
  • size: 112 kB
  • sloc: makefile: 2
file content (98 lines) | stat: -rw-r--r-- 2,510 bytes parent folder | download
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
}