go.charczuk.com@v0.0.0-20240327042549-bc490516bd1a/sdk/errutil/new.go (about)

     1  /*
     2  
     3  Copyright (c) 2023 - Present. Will Charczuk. All rights reserved.
     4  Use of this source code is governed by a MIT license that can be found in the LICENSE file at the root of the repository.
     5  
     6  */
     7  
     8  package errutil
     9  
    10  import (
    11  	"encoding/json"
    12  	"errors"
    13  	"fmt"
    14  )
    15  
    16  var (
    17  	_ error          = (*Exception)(nil)
    18  	_ fmt.Formatter  = (*Exception)(nil)
    19  	_ json.Marshaler = (*Exception)(nil)
    20  )
    21  
    22  // New returns a new error with a call stack.
    23  //
    24  // Pragma: this violates the rule that you should take interfaces and return
    25  // concrete types intentionally; it is important for the semantics of typed pointers and nil
    26  // for this to return an interface because (*Ex)(nil) != nil, but (error)(nil) == nil.
    27  func New(class interface{}, options ...Option) error {
    28  	return NewDepth(class, DefaultErrorStartDepth, options...)
    29  }
    30  
    31  // NewDepth creates a new exception with a given start point of the stack.
    32  func NewDepth(class interface{}, startDepth int, options ...Option) error {
    33  	if class == nil {
    34  		return nil
    35  	}
    36  
    37  	var ex *Exception
    38  	switch typed := class.(type) {
    39  	case *Exception:
    40  		if typed == nil {
    41  			return nil
    42  		}
    43  		ex = typed
    44  	case error:
    45  		if typed == nil {
    46  			return nil
    47  		}
    48  
    49  		ex = &Exception{
    50  			Class:      typed,
    51  			Inner:      errors.Unwrap(typed),
    52  			StackTrace: Callers(startDepth),
    53  		}
    54  	case string:
    55  		ex = &Exception{
    56  			Class:      Class(typed),
    57  			StackTrace: Callers(startDepth),
    58  		}
    59  	default:
    60  		ex = &Exception{
    61  			Class:      Class(fmt.Sprint(class)),
    62  			StackTrace: Callers(startDepth),
    63  		}
    64  	}
    65  	for _, option := range options {
    66  		option(ex)
    67  	}
    68  	return ex
    69  }