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  }