gitee.com/hongliu9527/go-tools@v0.0.8/errors/gerror/gerror_error.go (about)

     1  /*
     2   * @Author: hongliu
     3   * @Date: 2022-12-29 10:51:12
     4   * @LastEditors: hongliu
     5   * @LastEditTime: 2022-12-29 11:32:14
     6   * @FilePath: \go-tools\errors\gerror\gerror_error.go
     7   * @Description:内部错误定义
     8   *
     9   * Copyright (c) 2022 by 洪流, All Rights Reserved.
    10   */
    11  
    12  package gerror
    13  
    14  import (
    15  	"errors"
    16  	"fmt"
    17  	"runtime"
    18  	"strings"
    19  
    20  	"gitee.com/hongliu9527/go-tools/errors/gcode"
    21  )
    22  
    23  // Error is custom error for additional features.
    24  type Error struct {
    25  	error error      // Wrapped error.
    26  	stack stack      // Stack array, which records the stack information when this error is created or wrapped.
    27  	text  string     // Custom Error text when Error is created, might be empty when its code is not nil.
    28  	code  gcode.Code // Error code if necessary.
    29  }
    30  
    31  const (
    32  	// Filtering key for current error module paths.
    33  	stackFilterKeyLocal = "/errors/gerror/gerror"
    34  )
    35  
    36  var (
    37  	// goRootForFilter is used for stack filtering in development environment purpose.
    38  	goRootForFilter = runtime.GOROOT()
    39  )
    40  
    41  func init() {
    42  	if goRootForFilter != "" {
    43  		goRootForFilter = strings.ReplaceAll(goRootForFilter, "\\", "/")
    44  	}
    45  }
    46  
    47  // Error implements the interface of Error, it returns all the error as string.
    48  func (err *Error) Error() string {
    49  	if err == nil {
    50  		return ""
    51  	}
    52  	errStr := err.text
    53  	if errStr == "" && err.code != nil {
    54  		errStr = err.code.Message()
    55  	}
    56  	if err.error != nil {
    57  		if errStr != "" {
    58  			errStr += ": "
    59  		}
    60  		errStr += err.error.Error()
    61  	}
    62  	return errStr
    63  }
    64  
    65  // Cause returns the root cause error.
    66  func (err *Error) Cause() error {
    67  	if err == nil {
    68  		return nil
    69  	}
    70  	loop := err
    71  	for loop != nil {
    72  		if loop.error != nil {
    73  			if e, ok := loop.error.(*Error); ok {
    74  				// Internal Error struct.
    75  				loop = e
    76  			} else if e, ok := loop.error.(ICause); ok {
    77  				// Other Error that implements ApiCause interface.
    78  				return e.Cause()
    79  			} else {
    80  				return loop.error
    81  			}
    82  		} else {
    83  			// return loop
    84  			//
    85  			// To be compatible with Case of https://github.com/pkg/errors.
    86  			return errors.New(loop.text)
    87  		}
    88  	}
    89  	return nil
    90  }
    91  
    92  // Current creates and returns the current level error.
    93  // It returns nil if current level error is nil.
    94  func (err *Error) Current() error {
    95  	if err == nil {
    96  		return nil
    97  	}
    98  	return &Error{
    99  		error: nil,
   100  		stack: err.stack,
   101  		text:  err.text,
   102  		code:  err.code,
   103  	}
   104  }
   105  
   106  // Unwrap is alias of function `Next`.
   107  // It is just for implements for stdlib errors.Unwrap from Go version 1.17.
   108  func (err *Error) Unwrap() error {
   109  	if err == nil {
   110  		return nil
   111  	}
   112  	return err.error
   113  }
   114  
   115  // Equal reports whether current error `err` equals to error `target`.
   116  // Please note that, in default comparison for `Error`,
   117  // the errors are considered the same if both the `code` and `text` of them are the same.
   118  func (err *Error) Equal(target error) bool {
   119  	if err == target {
   120  		return true
   121  	}
   122  	// Code should be the same.
   123  	// Note that if both errors have `nil` code, they are also considered equal.
   124  	if err.code != Code(target) {
   125  		return false
   126  	}
   127  	// Text should be the same.
   128  	if err.text != fmt.Sprintf(`%-s`, target) {
   129  		return false
   130  	}
   131  	return true
   132  }
   133  
   134  // Is reports whether current error `err` has error `target` in its chaining errors.
   135  // It is just for implements for stdlib errors.Is from Go version 1.17.
   136  func (err *Error) Is(target error) bool {
   137  	if Equal(err, target) {
   138  		return true
   139  	}
   140  	nextErr := err.Unwrap()
   141  	if nextErr == nil {
   142  		return false
   143  	}
   144  	if Equal(nextErr, target) {
   145  		return true
   146  	}
   147  	if e, ok := nextErr.(IIs); ok {
   148  		return e.Is(target)
   149  	}
   150  	return false
   151  }