mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2024-05-20 09:18:13 +00:00
249 lines
5.2 KiB
Go
249 lines
5.2 KiB
Go
package errors
|
|
|
|
import (
|
|
"fmt"
|
|
"runtime"
|
|
)
|
|
|
|
// New returns a new error created from message.
|
|
//
|
|
// Note this function cannot be inlined, to ensure expected
|
|
// and consistent behaviour in setting trace / caller info.
|
|
//
|
|
//go:noinline
|
|
func New(msg string) error {
|
|
var c caller
|
|
var t trace
|
|
if IncludesCaller {
|
|
pcs := make([]uintptr, 1)
|
|
_ = runtime.Callers(2, pcs)
|
|
fn := runtime.FuncForPC(pcs[0])
|
|
c.set(funcName(fn))
|
|
}
|
|
if IncludesStacktrace {
|
|
pcs := make([]uintptr, 10)
|
|
n := runtime.Callers(2, pcs)
|
|
iter := runtime.CallersFrames(pcs[:n])
|
|
t.set(gatherFrames(iter, n))
|
|
}
|
|
return &_errormsg{
|
|
cfn: c,
|
|
msg: msg,
|
|
trc: t,
|
|
}
|
|
}
|
|
|
|
// Newf returns a new error created from message format and args.
|
|
//
|
|
// Note this function cannot be inlined, to ensure expected
|
|
// and consistent behaviour in setting trace / caller info.
|
|
//
|
|
//go:noinline
|
|
func Newf(msgf string, args ...interface{}) error {
|
|
var c caller
|
|
var t trace
|
|
if IncludesCaller {
|
|
pcs := make([]uintptr, 1)
|
|
_ = runtime.Callers(2, pcs)
|
|
fn := runtime.FuncForPC(pcs[0])
|
|
c.set(funcName(fn))
|
|
}
|
|
if IncludesStacktrace {
|
|
pcs := make([]uintptr, 10)
|
|
n := runtime.Callers(2, pcs)
|
|
iter := runtime.CallersFrames(pcs[:n])
|
|
t.set(gatherFrames(iter, n))
|
|
}
|
|
return &_errormsg{
|
|
cfn: c,
|
|
msg: fmt.Sprintf(msgf, args...),
|
|
trc: t,
|
|
}
|
|
}
|
|
|
|
// NewAt returns a new error created, skipping 'skip'
|
|
// frames for trace / caller information, from message.
|
|
//
|
|
// Note this function cannot be inlined, to ensure expected
|
|
// and consistent behaviour in setting trace / caller info.
|
|
//
|
|
//go:noinline
|
|
func NewAt(skip int, msg string) error {
|
|
var c caller
|
|
var t trace
|
|
if IncludesCaller {
|
|
pcs := make([]uintptr, 1)
|
|
_ = runtime.Callers(skip+1, pcs)
|
|
fn := runtime.FuncForPC(pcs[0])
|
|
c.set(funcName(fn))
|
|
}
|
|
if IncludesStacktrace {
|
|
pcs := make([]uintptr, 10)
|
|
n := runtime.Callers(skip+1, pcs)
|
|
iter := runtime.CallersFrames(pcs[:n])
|
|
t.set(gatherFrames(iter, n))
|
|
}
|
|
return &_errormsg{
|
|
cfn: c,
|
|
msg: msg,
|
|
trc: t,
|
|
}
|
|
}
|
|
|
|
// Wrap will wrap supplied error within a new error created from message.
|
|
//
|
|
// Note this function cannot be inlined, to ensure expected
|
|
// and consistent behaviour in setting trace / caller info.
|
|
//
|
|
//go:noinline
|
|
func Wrap(err error, msg string) error {
|
|
if err == nil {
|
|
panic("cannot wrap nil error")
|
|
}
|
|
var c caller
|
|
var t trace
|
|
if IncludesCaller {
|
|
pcs := make([]uintptr, 1)
|
|
_ = runtime.Callers(2, pcs)
|
|
fn := runtime.FuncForPC(pcs[0])
|
|
c.set(funcName(fn))
|
|
}
|
|
if IncludesStacktrace {
|
|
pcs := make([]uintptr, 10)
|
|
n := runtime.Callers(2, pcs)
|
|
iter := runtime.CallersFrames(pcs[:n])
|
|
t.set(gatherFrames(iter, n))
|
|
}
|
|
return &_errorwrap{
|
|
cfn: c,
|
|
msg: msg,
|
|
err: err,
|
|
trc: t,
|
|
}
|
|
}
|
|
|
|
// Wrapf will wrap supplied error within a new error created from message format and args.
|
|
//
|
|
// Note this function cannot be inlined, to ensure expected
|
|
// and consistent behaviour in setting trace / caller info.
|
|
//
|
|
//go:noinline
|
|
func Wrapf(err error, msgf string, args ...interface{}) error {
|
|
if err == nil {
|
|
panic("cannot wrap nil error")
|
|
}
|
|
var c caller
|
|
var t trace
|
|
if IncludesCaller {
|
|
pcs := make([]uintptr, 1)
|
|
_ = runtime.Callers(2, pcs)
|
|
fn := runtime.FuncForPC(pcs[0])
|
|
c.set(funcName(fn))
|
|
}
|
|
if IncludesStacktrace {
|
|
pcs := make([]uintptr, 10)
|
|
n := runtime.Callers(2, pcs)
|
|
iter := runtime.CallersFrames(pcs[:n])
|
|
t.set(gatherFrames(iter, n))
|
|
}
|
|
return &_errorwrap{
|
|
cfn: c,
|
|
msg: fmt.Sprintf(msgf, args...),
|
|
err: err,
|
|
trc: t,
|
|
}
|
|
}
|
|
|
|
// WrapAt wraps error within new error created from message,
|
|
// skipping 'skip' frames for trace / caller information.
|
|
//
|
|
// Note this function cannot be inlined, to ensure expected
|
|
// and consistent behaviour in setting trace / caller info.
|
|
//
|
|
//go:noinline
|
|
func WrapAt(skip int, err error, msg string) error {
|
|
if err == nil {
|
|
panic("cannot wrap nil error")
|
|
}
|
|
var c caller
|
|
var t trace
|
|
if IncludesCaller {
|
|
pcs := make([]uintptr, 1)
|
|
_ = runtime.Callers(skip+1, pcs)
|
|
fn := runtime.FuncForPC(pcs[0])
|
|
c.set(funcName(fn))
|
|
}
|
|
if IncludesStacktrace {
|
|
pcs := make([]uintptr, 10)
|
|
n := runtime.Callers(skip+1, pcs)
|
|
iter := runtime.CallersFrames(pcs[:n])
|
|
t.set(gatherFrames(iter, n))
|
|
}
|
|
return &_errorwrap{
|
|
cfn: c,
|
|
msg: msg,
|
|
err: err,
|
|
trc: t,
|
|
}
|
|
}
|
|
|
|
// Stacktrace fetches first stored stacktrace of callers from error chain.
|
|
func Stacktrace(err error) Callers {
|
|
if !IncludesStacktrace {
|
|
// compile-time check
|
|
return nil
|
|
}
|
|
if e := AsV2[*_errormsg](err); err != nil {
|
|
return e.trc.value()
|
|
}
|
|
if e := AsV2[*_errorwrap](err); err != nil {
|
|
return e.trc.value()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type _errormsg struct {
|
|
cfn caller
|
|
msg string
|
|
trc trace
|
|
}
|
|
|
|
func (err *_errormsg) Error() string {
|
|
if IncludesCaller {
|
|
fn := err.cfn.value()
|
|
return fn + " " + err.msg
|
|
} else {
|
|
return err.msg
|
|
}
|
|
}
|
|
|
|
func (err *_errormsg) Is(other error) bool {
|
|
oerr, ok := other.(*_errormsg)
|
|
return ok && oerr.msg == err.msg
|
|
}
|
|
|
|
type _errorwrap struct {
|
|
cfn caller
|
|
msg string
|
|
err error // wrapped
|
|
trc trace
|
|
}
|
|
|
|
func (err *_errorwrap) Error() string {
|
|
if IncludesCaller {
|
|
fn := err.cfn.value()
|
|
return fn + " " + err.msg + ": " + err.err.Error()
|
|
} else {
|
|
return err.msg + ": " + err.err.Error()
|
|
}
|
|
}
|
|
|
|
func (err *_errorwrap) Is(other error) bool {
|
|
oerr, ok := other.(*_errorwrap)
|
|
return ok && oerr.msg == err.msg
|
|
}
|
|
|
|
func (err *_errorwrap) Unwrap() error {
|
|
return err.err
|
|
}
|