codeberg.org/gruf/go-errors/v2@v2.3.1/errors.go (about) 1 package errors 2 3 import ( 4 "fmt" 5 "runtime" 6 ) 7 8 // New returns a new error created from message. 9 // 10 // Note this function cannot be inlined, to ensure expected 11 // and consistent behaviour in setting trace / caller info. 12 // 13 //go:noinline 14 func New(msg string) error { 15 var c caller 16 var t trace 17 if IncludesCaller { 18 pcs := make([]uintptr, 1) 19 _ = runtime.Callers(2, pcs) 20 fn := runtime.FuncForPC(pcs[0]) 21 c.set(funcName(fn)) 22 } 23 if IncludesStacktrace { 24 pcs := make([]uintptr, 10) 25 n := runtime.Callers(2, pcs) 26 iter := runtime.CallersFrames(pcs[:n]) 27 t.set(gatherFrames(iter, n)) 28 } 29 return &_errormsg{ 30 cfn: c, 31 msg: msg, 32 trc: t, 33 } 34 } 35 36 // Newf returns a new error created from message format and args. 37 // 38 // Note this function cannot be inlined, to ensure expected 39 // and consistent behaviour in setting trace / caller info. 40 // 41 //go:noinline 42 func Newf(msgf string, args ...interface{}) error { 43 var c caller 44 var t trace 45 if IncludesCaller { 46 pcs := make([]uintptr, 1) 47 _ = runtime.Callers(2, pcs) 48 fn := runtime.FuncForPC(pcs[0]) 49 c.set(funcName(fn)) 50 } 51 if IncludesStacktrace { 52 pcs := make([]uintptr, 10) 53 n := runtime.Callers(2, pcs) 54 iter := runtime.CallersFrames(pcs[:n]) 55 t.set(gatherFrames(iter, n)) 56 } 57 return &_errormsg{ 58 cfn: c, 59 msg: fmt.Sprintf(msgf, args...), 60 trc: t, 61 } 62 } 63 64 // NewAt returns a new error created, skipping 'skip' 65 // frames for trace / caller information, from message. 66 // 67 // Note this function cannot be inlined, to ensure expected 68 // and consistent behaviour in setting trace / caller info. 69 // 70 //go:noinline 71 func NewAt(skip int, msg string) error { 72 var c caller 73 var t trace 74 if IncludesCaller { 75 pcs := make([]uintptr, 1) 76 _ = runtime.Callers(skip+1, pcs) 77 fn := runtime.FuncForPC(pcs[0]) 78 c.set(funcName(fn)) 79 } 80 if IncludesStacktrace { 81 pcs := make([]uintptr, 10) 82 n := runtime.Callers(skip+1, pcs) 83 iter := runtime.CallersFrames(pcs[:n]) 84 t.set(gatherFrames(iter, n)) 85 } 86 return &_errormsg{ 87 cfn: c, 88 msg: msg, 89 trc: t, 90 } 91 } 92 93 // Wrap will wrap supplied error within a new error created from message. 94 // 95 // Note this function cannot be inlined, to ensure expected 96 // and consistent behaviour in setting trace / caller info. 97 // 98 //go:noinline 99 func Wrap(err error, msg string) error { 100 if err == nil { 101 panic("cannot wrap nil error") 102 } 103 var c caller 104 var t trace 105 if IncludesCaller { 106 pcs := make([]uintptr, 1) 107 _ = runtime.Callers(2, pcs) 108 fn := runtime.FuncForPC(pcs[0]) 109 c.set(funcName(fn)) 110 } 111 if IncludesStacktrace { 112 pcs := make([]uintptr, 10) 113 n := runtime.Callers(2, pcs) 114 iter := runtime.CallersFrames(pcs[:n]) 115 t.set(gatherFrames(iter, n)) 116 } 117 return &_errorwrap{ 118 cfn: c, 119 msg: msg, 120 err: err, 121 trc: t, 122 } 123 } 124 125 // Wrapf will wrap supplied error within a new error created from message format and args. 126 // 127 // Note this function cannot be inlined, to ensure expected 128 // and consistent behaviour in setting trace / caller info. 129 // 130 //go:noinline 131 func Wrapf(err error, msgf string, args ...interface{}) error { 132 if err == nil { 133 panic("cannot wrap nil error") 134 } 135 var c caller 136 var t trace 137 if IncludesCaller { 138 pcs := make([]uintptr, 1) 139 _ = runtime.Callers(2, pcs) 140 fn := runtime.FuncForPC(pcs[0]) 141 c.set(funcName(fn)) 142 } 143 if IncludesStacktrace { 144 pcs := make([]uintptr, 10) 145 n := runtime.Callers(2, pcs) 146 iter := runtime.CallersFrames(pcs[:n]) 147 t.set(gatherFrames(iter, n)) 148 } 149 return &_errorwrap{ 150 cfn: c, 151 msg: fmt.Sprintf(msgf, args...), 152 err: err, 153 trc: t, 154 } 155 } 156 157 // WrapAt wraps error within new error created from message, 158 // skipping 'skip' frames for trace / caller information. 159 // 160 // Note this function cannot be inlined, to ensure expected 161 // and consistent behaviour in setting trace / caller info. 162 // 163 //go:noinline 164 func WrapAt(skip int, err error, msg string) error { 165 if err == nil { 166 panic("cannot wrap nil error") 167 } 168 var c caller 169 var t trace 170 if IncludesCaller { 171 pcs := make([]uintptr, 1) 172 _ = runtime.Callers(skip+1, pcs) 173 fn := runtime.FuncForPC(pcs[0]) 174 c.set(funcName(fn)) 175 } 176 if IncludesStacktrace { 177 pcs := make([]uintptr, 10) 178 n := runtime.Callers(skip+1, pcs) 179 iter := runtime.CallersFrames(pcs[:n]) 180 t.set(gatherFrames(iter, n)) 181 } 182 return &_errorwrap{ 183 cfn: c, 184 msg: msg, 185 err: err, 186 trc: t, 187 } 188 } 189 190 // Stacktrace fetches first stored stacktrace of callers from error chain. 191 func Stacktrace(err error) Callers { 192 if !IncludesStacktrace { 193 // compile-time check 194 return nil 195 } 196 if e := AsV2[*_errormsg](err); err != nil { 197 return e.trc.value() 198 } 199 if e := AsV2[*_errorwrap](err); err != nil { 200 return e.trc.value() 201 } 202 return nil 203 } 204 205 type _errormsg struct { 206 cfn caller 207 msg string 208 trc trace 209 } 210 211 func (err *_errormsg) Error() string { 212 if IncludesCaller { 213 fn := err.cfn.value() 214 return fn + " " + err.msg 215 } else { 216 return err.msg 217 } 218 } 219 220 func (err *_errormsg) Is(other error) bool { 221 oerr, ok := other.(*_errormsg) 222 return ok && oerr.msg == err.msg 223 } 224 225 type _errorwrap struct { 226 cfn caller 227 msg string 228 err error // wrapped 229 trc trace 230 } 231 232 func (err *_errorwrap) Error() string { 233 if IncludesCaller { 234 fn := err.cfn.value() 235 return fn + " " + err.msg + ": " + err.err.Error() 236 } else { 237 return err.msg + ": " + err.err.Error() 238 } 239 } 240 241 func (err *_errorwrap) Is(other error) bool { 242 oerr, ok := other.(*_errorwrap) 243 return ok && oerr.msg == err.msg 244 } 245 246 func (err *_errorwrap) Unwrap() error { 247 return err.err 248 }