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  }