github.com/nikandfor/errors@v0.8.0/errors.go (about) 1 package errors 2 3 import ( 4 "fmt" 5 6 "github.com/nikandfor/loc" 7 ) 8 9 type ( 10 // PC is a program counter and represents location in a source code. 11 PC = loc.PC 12 PCs = loc.PCs 13 14 wrapper struct { 15 err error 16 msg string 17 } 18 19 withPC struct { 20 wrapper 21 pc PC 22 } 23 24 withPCs struct { 25 wrapper 26 pcs PCs 27 } 28 29 Callerer interface { 30 Caller() PC 31 } 32 33 Callerser interface { 34 Callers() PCs 35 } 36 ) 37 38 const nomessage = "(no message)" 39 40 // New returns an error that formats as the given text. 41 // Each call to New returns a distinct error value even if the text is identical. 42 func New(f string, args ...interface{}) error { 43 return withPC{ 44 wrapper: wrapper{ 45 msg: fmt.Sprintf(f, args...), 46 }, 47 pc: loc.Caller(1), 48 } 49 } 50 51 // NewNoCaller is like a New but with no caller info. 52 func NewNoCaller(f string, args ...interface{}) error { 53 return wrapper{ 54 msg: fmt.Sprintf(f, args...), 55 } 56 } 57 58 // NewDepth returns an error that formats as the given text. 59 // Callsite where error was created (d frames higher) is recorded. 60 // Each call to New returns a distinct error value even if the text is identical. 61 func NewDepth(d int, f string, args ...interface{}) error { 62 return withPC{ 63 wrapper: wrapper{ 64 msg: fmt.Sprintf(f, args...), 65 }, 66 pc: loc.Caller(d + 1), 67 } 68 } 69 70 // NewStack returns an error with message formatted in fmt package style. 71 // Caller frames are recorded (skipping d frames). 72 // Experimental, may be deleted at any time. 73 func NewStack(skip, n int, f string, args ...interface{}) error { 74 return withPCs{ 75 wrapper: wrapper{ 76 msg: fmt.Sprintf(f, args...), 77 }, 78 pcs: loc.Callers(skip+1, n), 79 } 80 } 81 82 // NewCaller returns an error with given PC that formats as the given text. 83 // Each call to New returns a distinct error value even if the text is identical. 84 func NewCaller(pc PC, f string, args ...interface{}) error { 85 return withPC{ 86 wrapper: wrapper{ 87 msg: fmt.Sprintf(f, args...), 88 }, 89 pc: pc, 90 } 91 } 92 93 // NewCallers returns an error with given PC that formats as the given text. 94 // Each call to New returns a distinct error value even if the text is identical. 95 // Experimental, may be deleted at any time. 96 func NewCallers(pcs PCs, f string, args ...interface{}) error { 97 return withPCs{ 98 wrapper: wrapper{ 99 msg: fmt.Sprintf(f, args...), 100 }, 101 pcs: pcs, 102 } 103 } 104 105 // Wrap returns an error that describes given error with given text. 106 // Returns nil if err is nil. 107 func Wrap(err error, f string, args ...interface{}) error { 108 if err == nil { 109 return nil 110 } 111 112 return withPC{ 113 wrapper: wrapper{ 114 err: err, 115 msg: fmt.Sprintf(f, args...), 116 }, 117 pc: loc.Caller(1), 118 } 119 } 120 121 // WrapNoCaller is like Wrap but without caller info. 122 func WrapNoCaller(err error, f string, args ...interface{}) error { 123 if err == nil { 124 return nil 125 } 126 127 return wrapper{ 128 err: err, 129 msg: fmt.Sprintf(f, args...), 130 } 131 } 132 133 // WrapDepth returns an error that describes given error with given text. 134 // Callsite where error was created (d frames higher) is recorded. 135 // Returns nil if err is nil. 136 func WrapDepth(err error, d int, f string, args ...interface{}) error { 137 if err == nil { 138 return nil 139 } 140 141 return withPC{ 142 wrapper: wrapper{ 143 err: err, 144 msg: fmt.Sprintf(f, args...), 145 }, 146 pc: loc.Caller(d + 1), 147 } 148 } 149 150 // Experimental, may be deleted at any time. 151 func WrapStack(err error, skip, n int, f string, args ...interface{}) error { 152 if err == nil { 153 return nil 154 } 155 156 return withPCs{ 157 wrapper: wrapper{ 158 err: err, 159 msg: fmt.Sprintf(f, args...), 160 }, 161 pcs: loc.Callers(skip+1, n), 162 } 163 } 164 165 // WrapCaller returns an error with given PC that describes given error with given text. 166 // Returns nil if err is nil. 167 func WrapCaller(err error, pc PC, f string, args ...interface{}) error { 168 if err == nil { 169 return nil 170 } 171 172 return withPC{ 173 wrapper: wrapper{ 174 err: err, 175 msg: fmt.Sprintf(f, args...), 176 }, 177 pc: pc, 178 } 179 } 180 181 // Experimental, may be deleted at any time. 182 func WrapCallers(err error, pcs PCs, f string, args ...interface{}) error { 183 if err == nil { 184 return nil 185 } 186 187 return withPCs{ 188 wrapper: wrapper{ 189 err: err, 190 msg: fmt.Sprintf(f, args...), 191 }, 192 pcs: pcs, 193 } 194 } 195 196 // Error is an error interface implementation. 197 func (e wrapper) Error() string { 198 if e.err == nil { 199 if e.msg == "" { 200 return nomessage 201 } 202 return e.msg 203 } 204 205 if e.msg == "" { 206 return e.err.Error() 207 } 208 209 return e.msg + ": " + e.err.Error() 210 } 211 212 // Unwrap returns original error that was wrapped or nil if it's not wrapper. 213 func (e wrapper) Unwrap() error { 214 return e.err 215 } 216 217 // Caller returns underlaying error location. 218 func (e withPC) Caller() PC { 219 return e.pc 220 } 221 222 // Caller returns underlaying error location. 223 func (e withPCs) Caller() PC { 224 if len(e.pcs) == 0 { 225 return 0 226 } 227 228 return e.pcs[0] 229 } 230 231 // Callers returns underlaying error location. 232 func (e withPCs) Callers() PCs { 233 return e.pcs 234 }