mirror of
https://gitee.com/johng/gf
synced 2026-06-06 02:25:47 +08:00
improve package gerror, add HasCode/HasError function for package gerror (#2006)
This commit is contained in:
@ -4,316 +4,55 @@
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package gerror provides simple functions to manipulate errors.
|
||||
// Package gerror provides rich functionalities to manipulate errors.
|
||||
//
|
||||
// Very note that, this package is quite a basic package, which SHOULD NOT import extra packages
|
||||
// For maintainers, please very note that,
|
||||
// this package is quite a basic package, which SHOULD NOT import extra packages
|
||||
// except standard packages and internal packages, to avoid cycle imports.
|
||||
package gerror
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
)
|
||||
|
||||
// New creates and returns an error which is formatted from given text.
|
||||
func New(text string) error {
|
||||
return &Error{
|
||||
stack: callers(),
|
||||
text: text,
|
||||
code: gcode.CodeNil,
|
||||
}
|
||||
// IIs is the interface for Is feature.
|
||||
type IIs interface {
|
||||
Error() string
|
||||
Is(target error) bool
|
||||
}
|
||||
|
||||
// Newf returns an error that formats as the given format and args.
|
||||
func Newf(format string, args ...interface{}) error {
|
||||
return &Error{
|
||||
stack: callers(),
|
||||
text: fmt.Sprintf(format, args...),
|
||||
code: gcode.CodeNil,
|
||||
}
|
||||
// IEqual is the interface for Equal feature.
|
||||
type IEqual interface {
|
||||
Error() string
|
||||
Equal(target error) bool
|
||||
}
|
||||
|
||||
// NewSkip creates and returns an error which is formatted from given text.
|
||||
// The parameter `skip` specifies the stack callers skipped amount.
|
||||
func NewSkip(skip int, text string) error {
|
||||
return &Error{
|
||||
stack: callers(skip),
|
||||
text: text,
|
||||
code: gcode.CodeNil,
|
||||
}
|
||||
// ICode is the interface for Code feature.
|
||||
type ICode interface {
|
||||
Error() string
|
||||
Code() gcode.Code
|
||||
}
|
||||
|
||||
// NewSkipf returns an error that formats as the given format and args.
|
||||
// The parameter `skip` specifies the stack callers skipped amount.
|
||||
func NewSkipf(skip int, format string, args ...interface{}) error {
|
||||
return &Error{
|
||||
stack: callers(skip),
|
||||
text: fmt.Sprintf(format, args...),
|
||||
code: gcode.CodeNil,
|
||||
}
|
||||
// IStack is the interface for Stack feature.
|
||||
type IStack interface {
|
||||
Error() string
|
||||
Stack() string
|
||||
}
|
||||
|
||||
// Wrap wraps error with text. It returns nil if given err is nil.
|
||||
// Note that it does not lose the error code of wrapped error, as it inherits the error code from it.
|
||||
func Wrap(err error, text string) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &Error{
|
||||
error: err,
|
||||
stack: callers(),
|
||||
text: text,
|
||||
code: Code(err),
|
||||
}
|
||||
// ICause is the interface for Cause feature.
|
||||
type ICause interface {
|
||||
Error() string
|
||||
Cause() error
|
||||
}
|
||||
|
||||
// Wrapf returns an error annotating err with a stack trace at the point Wrapf is called, and the format specifier.
|
||||
// It returns nil if given `err` is nil.
|
||||
// Note that it does not lose the error code of wrapped error, as it inherits the error code from it.
|
||||
func Wrapf(err error, format string, args ...interface{}) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &Error{
|
||||
error: err,
|
||||
stack: callers(),
|
||||
text: fmt.Sprintf(format, args...),
|
||||
code: Code(err),
|
||||
}
|
||||
// ICurrent is the interface for Current feature.
|
||||
type ICurrent interface {
|
||||
Error() string
|
||||
Current() error
|
||||
}
|
||||
|
||||
// WrapSkip wraps error with text. It returns nil if given err is nil.
|
||||
// The parameter `skip` specifies the stack callers skipped amount.
|
||||
// Note that it does not lose the error code of wrapped error, as it inherits the error code from it.
|
||||
func WrapSkip(skip int, err error, text string) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &Error{
|
||||
error: err,
|
||||
stack: callers(skip),
|
||||
text: text,
|
||||
code: Code(err),
|
||||
}
|
||||
}
|
||||
|
||||
// WrapSkipf wraps error with text that is formatted with given format and args. It returns nil if given err is nil.
|
||||
// The parameter `skip` specifies the stack callers skipped amount.
|
||||
// Note that it does not lose the error code of wrapped error, as it inherits the error code from it.
|
||||
func WrapSkipf(skip int, err error, format string, args ...interface{}) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &Error{
|
||||
error: err,
|
||||
stack: callers(skip),
|
||||
text: fmt.Sprintf(format, args...),
|
||||
code: Code(err),
|
||||
}
|
||||
}
|
||||
|
||||
// NewCode creates and returns an error that has error code and given text.
|
||||
func NewCode(code gcode.Code, text ...string) error {
|
||||
return &Error{
|
||||
stack: callers(),
|
||||
text: strings.Join(text, ", "),
|
||||
code: code,
|
||||
}
|
||||
}
|
||||
|
||||
// NewCodef returns an error that has error code and formats as the given format and args.
|
||||
func NewCodef(code gcode.Code, format string, args ...interface{}) error {
|
||||
return &Error{
|
||||
stack: callers(),
|
||||
text: fmt.Sprintf(format, args...),
|
||||
code: code,
|
||||
}
|
||||
}
|
||||
|
||||
// NewCodeSkip creates and returns an error which has error code and is formatted from given text.
|
||||
// The parameter `skip` specifies the stack callers skipped amount.
|
||||
func NewCodeSkip(code gcode.Code, skip int, text ...string) error {
|
||||
return &Error{
|
||||
stack: callers(skip),
|
||||
text: strings.Join(text, ", "),
|
||||
code: code,
|
||||
}
|
||||
}
|
||||
|
||||
// NewCodeSkipf returns an error that has error code and formats as the given format and args.
|
||||
// The parameter `skip` specifies the stack callers skipped amount.
|
||||
func NewCodeSkipf(code gcode.Code, skip int, format string, args ...interface{}) error {
|
||||
return &Error{
|
||||
stack: callers(skip),
|
||||
text: fmt.Sprintf(format, args...),
|
||||
code: code,
|
||||
}
|
||||
}
|
||||
|
||||
// WrapCode wraps error with code and text.
|
||||
// It returns nil if given err is nil.
|
||||
func WrapCode(code gcode.Code, err error, text ...string) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &Error{
|
||||
error: err,
|
||||
stack: callers(),
|
||||
text: strings.Join(text, ", "),
|
||||
code: code,
|
||||
}
|
||||
}
|
||||
|
||||
// WrapCodef wraps error with code and format specifier.
|
||||
// It returns nil if given `err` is nil.
|
||||
func WrapCodef(code gcode.Code, err error, format string, args ...interface{}) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &Error{
|
||||
error: err,
|
||||
stack: callers(),
|
||||
text: fmt.Sprintf(format, args...),
|
||||
code: code,
|
||||
}
|
||||
}
|
||||
|
||||
// WrapCodeSkip wraps error with code and text.
|
||||
// It returns nil if given err is nil.
|
||||
// The parameter `skip` specifies the stack callers skipped amount.
|
||||
func WrapCodeSkip(code gcode.Code, skip int, err error, text ...string) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &Error{
|
||||
error: err,
|
||||
stack: callers(skip),
|
||||
text: strings.Join(text, ", "),
|
||||
code: code,
|
||||
}
|
||||
}
|
||||
|
||||
// WrapCodeSkipf wraps error with code and text that is formatted with given format and args.
|
||||
// It returns nil if given err is nil.
|
||||
// The parameter `skip` specifies the stack callers skipped amount.
|
||||
func WrapCodeSkipf(code gcode.Code, skip int, err error, format string, args ...interface{}) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &Error{
|
||||
error: err,
|
||||
stack: callers(skip),
|
||||
text: fmt.Sprintf(format, args...),
|
||||
code: code,
|
||||
}
|
||||
}
|
||||
|
||||
// Code returns the error code of current error.
|
||||
// It returns CodeNil if it has no error code neither it does not implement interface Code.
|
||||
func Code(err error) gcode.Code {
|
||||
if err == nil {
|
||||
return gcode.CodeNil
|
||||
}
|
||||
if e, ok := err.(iCode); ok {
|
||||
return e.Code()
|
||||
}
|
||||
if e, ok := err.(iNext); ok {
|
||||
return Code(e.Next())
|
||||
}
|
||||
if e, ok := err.(iUnwrap); ok {
|
||||
return Code(e.Unwrap())
|
||||
}
|
||||
return gcode.CodeNil
|
||||
}
|
||||
|
||||
// Cause returns the root cause error of `err`.
|
||||
func Cause(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if e, ok := err.(iCause); ok {
|
||||
return e.Cause()
|
||||
}
|
||||
if e, ok := err.(iNext); ok {
|
||||
return Cause(e.Next())
|
||||
}
|
||||
if e, ok := err.(iUnwrap); ok {
|
||||
return Cause(e.Unwrap())
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Stack returns the stack callers as string.
|
||||
// It returns the error string directly if the `err` does not support stacks.
|
||||
func Stack(err error) string {
|
||||
if err == nil {
|
||||
return ""
|
||||
}
|
||||
if e, ok := err.(iStack); ok {
|
||||
return e.Stack()
|
||||
}
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
// Current creates and returns the current level error.
|
||||
// It returns nil if current level error is nil.
|
||||
func Current(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if e, ok := err.(iCurrent); ok {
|
||||
return e.Current()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Next returns the next level error.
|
||||
// It returns nil if current level error or the next level error is nil.
|
||||
func Next(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if e, ok := err.(iNext); ok {
|
||||
return e.Next()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unwrap is alias of function `Next`.
|
||||
// It is just for implements for stdlib errors.Unwrap from Go version 1.17.
|
||||
func Unwrap(err error) error {
|
||||
return Next(err)
|
||||
}
|
||||
|
||||
// HasStack checks and returns whether `err` implemented interface `iStack`.
|
||||
func HasStack(err error) bool {
|
||||
_, ok := err.(iStack)
|
||||
return ok
|
||||
}
|
||||
|
||||
// Equal reports whether current error `err` equals to error `target`.
|
||||
// Please note that, in default comparison for `Error`,
|
||||
// the errors are considered the same if both the `code` and `text` of them are the same.
|
||||
func Equal(err, target error) bool {
|
||||
if err == target {
|
||||
return true
|
||||
}
|
||||
if e, ok := err.(iEqual); ok {
|
||||
return e.Equal(target)
|
||||
}
|
||||
if e, ok := target.(iEqual); ok {
|
||||
return e.Equal(err)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Is reports whether current error `err` has error `target` in its chaining errors.
|
||||
// It is just for implements for stdlib errors.Unwrap from Go version 1.17.
|
||||
func Is(err, target error) bool {
|
||||
if e, ok := err.(iIs); ok {
|
||||
return e.Is(target)
|
||||
}
|
||||
return false
|
||||
// IUnwrap is the interface for Unwrap feature.
|
||||
type IUnwrap interface {
|
||||
Error() string
|
||||
Unwrap() error
|
||||
}
|
||||
|
||||
110
errors/gerror/gerror_api.go
Normal file
110
errors/gerror/gerror_api.go
Normal file
@ -0,0 +1,110 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gerror
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
)
|
||||
|
||||
// New creates and returns an error which is formatted from given text.
|
||||
func New(text string) error {
|
||||
return &Error{
|
||||
stack: callers(),
|
||||
text: text,
|
||||
code: gcode.CodeNil,
|
||||
}
|
||||
}
|
||||
|
||||
// Newf returns an error that formats as the given format and args.
|
||||
func Newf(format string, args ...interface{}) error {
|
||||
return &Error{
|
||||
stack: callers(),
|
||||
text: fmt.Sprintf(format, args...),
|
||||
code: gcode.CodeNil,
|
||||
}
|
||||
}
|
||||
|
||||
// NewSkip creates and returns an error which is formatted from given text.
|
||||
// The parameter `skip` specifies the stack callers skipped amount.
|
||||
func NewSkip(skip int, text string) error {
|
||||
return &Error{
|
||||
stack: callers(skip),
|
||||
text: text,
|
||||
code: gcode.CodeNil,
|
||||
}
|
||||
}
|
||||
|
||||
// NewSkipf returns an error that formats as the given format and args.
|
||||
// The parameter `skip` specifies the stack callers skipped amount.
|
||||
func NewSkipf(skip int, format string, args ...interface{}) error {
|
||||
return &Error{
|
||||
stack: callers(skip),
|
||||
text: fmt.Sprintf(format, args...),
|
||||
code: gcode.CodeNil,
|
||||
}
|
||||
}
|
||||
|
||||
// Wrap wraps error with text. It returns nil if given err is nil.
|
||||
// Note that it does not lose the error code of wrapped error, as it inherits the error code from it.
|
||||
func Wrap(err error, text string) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &Error{
|
||||
error: err,
|
||||
stack: callers(),
|
||||
text: text,
|
||||
code: Code(err),
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapf returns an error annotating err with a stack trace at the point Wrapf is called, and the format specifier.
|
||||
// It returns nil if given `err` is nil.
|
||||
// Note that it does not lose the error code of wrapped error, as it inherits the error code from it.
|
||||
func Wrapf(err error, format string, args ...interface{}) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &Error{
|
||||
error: err,
|
||||
stack: callers(),
|
||||
text: fmt.Sprintf(format, args...),
|
||||
code: Code(err),
|
||||
}
|
||||
}
|
||||
|
||||
// WrapSkip wraps error with text. It returns nil if given err is nil.
|
||||
// The parameter `skip` specifies the stack callers skipped amount.
|
||||
// Note that it does not lose the error code of wrapped error, as it inherits the error code from it.
|
||||
func WrapSkip(skip int, err error, text string) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &Error{
|
||||
error: err,
|
||||
stack: callers(skip),
|
||||
text: text,
|
||||
code: Code(err),
|
||||
}
|
||||
}
|
||||
|
||||
// WrapSkipf wraps error with text that is formatted with given format and args. It returns nil if given err is nil.
|
||||
// The parameter `skip` specifies the stack callers skipped amount.
|
||||
// Note that it does not lose the error code of wrapped error, as it inherits the error code from it.
|
||||
func WrapSkipf(skip int, err error, format string, args ...interface{}) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &Error{
|
||||
error: err,
|
||||
stack: callers(skip),
|
||||
text: fmt.Sprintf(format, args...),
|
||||
code: Code(err),
|
||||
}
|
||||
}
|
||||
139
errors/gerror/gerror_api_code.go
Normal file
139
errors/gerror/gerror_api_code.go
Normal file
@ -0,0 +1,139 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gerror
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
)
|
||||
|
||||
// NewCode creates and returns an error that has error code and given text.
|
||||
func NewCode(code gcode.Code, text ...string) error {
|
||||
return &Error{
|
||||
stack: callers(),
|
||||
text: strings.Join(text, ", "),
|
||||
code: code,
|
||||
}
|
||||
}
|
||||
|
||||
// NewCodef returns an error that has error code and formats as the given format and args.
|
||||
func NewCodef(code gcode.Code, format string, args ...interface{}) error {
|
||||
return &Error{
|
||||
stack: callers(),
|
||||
text: fmt.Sprintf(format, args...),
|
||||
code: code,
|
||||
}
|
||||
}
|
||||
|
||||
// NewCodeSkip creates and returns an error which has error code and is formatted from given text.
|
||||
// The parameter `skip` specifies the stack callers skipped amount.
|
||||
func NewCodeSkip(code gcode.Code, skip int, text ...string) error {
|
||||
return &Error{
|
||||
stack: callers(skip),
|
||||
text: strings.Join(text, ", "),
|
||||
code: code,
|
||||
}
|
||||
}
|
||||
|
||||
// NewCodeSkipf returns an error that has error code and formats as the given format and args.
|
||||
// The parameter `skip` specifies the stack callers skipped amount.
|
||||
func NewCodeSkipf(code gcode.Code, skip int, format string, args ...interface{}) error {
|
||||
return &Error{
|
||||
stack: callers(skip),
|
||||
text: fmt.Sprintf(format, args...),
|
||||
code: code,
|
||||
}
|
||||
}
|
||||
|
||||
// WrapCode wraps error with code and text.
|
||||
// It returns nil if given err is nil.
|
||||
func WrapCode(code gcode.Code, err error, text ...string) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &Error{
|
||||
error: err,
|
||||
stack: callers(),
|
||||
text: strings.Join(text, ", "),
|
||||
code: code,
|
||||
}
|
||||
}
|
||||
|
||||
// WrapCodef wraps error with code and format specifier.
|
||||
// It returns nil if given `err` is nil.
|
||||
func WrapCodef(code gcode.Code, err error, format string, args ...interface{}) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &Error{
|
||||
error: err,
|
||||
stack: callers(),
|
||||
text: fmt.Sprintf(format, args...),
|
||||
code: code,
|
||||
}
|
||||
}
|
||||
|
||||
// WrapCodeSkip wraps error with code and text.
|
||||
// It returns nil if given err is nil.
|
||||
// The parameter `skip` specifies the stack callers skipped amount.
|
||||
func WrapCodeSkip(code gcode.Code, skip int, err error, text ...string) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &Error{
|
||||
error: err,
|
||||
stack: callers(skip),
|
||||
text: strings.Join(text, ", "),
|
||||
code: code,
|
||||
}
|
||||
}
|
||||
|
||||
// WrapCodeSkipf wraps error with code and text that is formatted with given format and args.
|
||||
// It returns nil if given err is nil.
|
||||
// The parameter `skip` specifies the stack callers skipped amount.
|
||||
func WrapCodeSkipf(code gcode.Code, skip int, err error, format string, args ...interface{}) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &Error{
|
||||
error: err,
|
||||
stack: callers(skip),
|
||||
text: fmt.Sprintf(format, args...),
|
||||
code: code,
|
||||
}
|
||||
}
|
||||
|
||||
// Code returns the error code of current error.
|
||||
// It returns `CodeNil` if it has no error code neither it does not implement interface Code.
|
||||
func Code(err error) gcode.Code {
|
||||
if err == nil {
|
||||
return gcode.CodeNil
|
||||
}
|
||||
if e, ok := err.(ICode); ok {
|
||||
return e.Code()
|
||||
}
|
||||
if e, ok := err.(IUnwrap); ok {
|
||||
return Code(e.Unwrap())
|
||||
}
|
||||
return gcode.CodeNil
|
||||
}
|
||||
|
||||
// HasCode checks and reports whether `err` has `code` in its chaining errors.
|
||||
func HasCode(err error, code gcode.Code) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
if e, ok := err.(ICode); ok {
|
||||
return code == e.Code()
|
||||
}
|
||||
if e, ok := err.(IUnwrap); ok {
|
||||
return HasCode(e.Unwrap(), code)
|
||||
}
|
||||
return false
|
||||
}
|
||||
118
errors/gerror/gerror_api_stack.go
Normal file
118
errors/gerror/gerror_api_stack.go
Normal file
@ -0,0 +1,118 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gerror
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// stack represents a stack of program counters.
|
||||
type stack []uintptr
|
||||
|
||||
const (
|
||||
// maxStackDepth marks the max stack depth for error back traces.
|
||||
maxStackDepth = 32
|
||||
)
|
||||
|
||||
// Cause returns the root cause error of `err`.
|
||||
func Cause(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if e, ok := err.(ICause); ok {
|
||||
return e.Cause()
|
||||
}
|
||||
if e, ok := err.(IUnwrap); ok {
|
||||
return Cause(e.Unwrap())
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Stack returns the stack callers as string.
|
||||
// It returns the error string directly if the `err` does not support stacks.
|
||||
func Stack(err error) string {
|
||||
if err == nil {
|
||||
return ""
|
||||
}
|
||||
if e, ok := err.(IStack); ok {
|
||||
return e.Stack()
|
||||
}
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
// Current creates and returns the current level error.
|
||||
// It returns nil if current level error is nil.
|
||||
func Current(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if e, ok := err.(ICurrent); ok {
|
||||
return e.Current()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Unwrap returns the next level error.
|
||||
// It returns nil if current level error or the next level error is nil.
|
||||
func Unwrap(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if e, ok := err.(IUnwrap); ok {
|
||||
return e.Unwrap()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// HasStack checks and reports whether `err` implemented interface `gerror.IStack`.
|
||||
func HasStack(err error) bool {
|
||||
_, ok := err.(IStack)
|
||||
return ok
|
||||
}
|
||||
|
||||
// Equal reports whether current error `err` equals to error `target`.
|
||||
// Please note that, in default comparison logic for `Error`,
|
||||
// the errors are considered the same if both the `code` and `text` of them are the same.
|
||||
func Equal(err, target error) bool {
|
||||
if err == target {
|
||||
return true
|
||||
}
|
||||
if e, ok := err.(IEqual); ok {
|
||||
return e.Equal(target)
|
||||
}
|
||||
if e, ok := target.(IEqual); ok {
|
||||
return e.Equal(err)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Is reports whether current error `err` has error `target` in its chaining errors.
|
||||
// It is just for implements for stdlib errors.Is from Go version 1.17.
|
||||
func Is(err, target error) bool {
|
||||
if e, ok := err.(IIs); ok {
|
||||
return e.Is(target)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// HasError is alias of Is, which more easily understanding semantics.
|
||||
func HasError(err, target error) bool {
|
||||
return Is(err, target)
|
||||
}
|
||||
|
||||
// callers returns the stack callers.
|
||||
// Note that it here just retrieves the caller memory address array not the caller information.
|
||||
func callers(skip ...int) stack {
|
||||
var (
|
||||
pcs [maxStackDepth]uintptr
|
||||
n = 3
|
||||
)
|
||||
if len(skip) > 0 {
|
||||
n += skip[0]
|
||||
}
|
||||
return pcs[:runtime.Callers(n, pcs[:])]
|
||||
}
|
||||
@ -68,7 +68,7 @@ func (err *Error) Cause() error {
|
||||
if e, ok := loop.error.(*Error); ok {
|
||||
// Internal Error struct.
|
||||
loop = e
|
||||
} else if e, ok := loop.error.(iCause); ok {
|
||||
} else if e, ok := loop.error.(ICause); ok {
|
||||
// Other Error that implements ApiCause interface.
|
||||
return e.Cause()
|
||||
} else {
|
||||
@ -76,6 +76,7 @@ func (err *Error) Cause() error {
|
||||
}
|
||||
} else {
|
||||
// return loop
|
||||
//
|
||||
// To be compatible with Case of https://github.com/pkg/errors.
|
||||
return errors.New(loop.text)
|
||||
}
|
||||
@ -97,21 +98,15 @@ func (err *Error) Current() error {
|
||||
}
|
||||
}
|
||||
|
||||
// Next returns the next level error.
|
||||
// It returns nil if current level error or the next level error is nil.
|
||||
func (err *Error) Next() error {
|
||||
// Unwrap is alias of function `Next`.
|
||||
// It is just for implements for stdlib errors.Unwrap from Go version 1.17.
|
||||
func (err *Error) Unwrap() error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return err.error
|
||||
}
|
||||
|
||||
// Unwrap is alias of function `Next`.
|
||||
// It is just for implements for stdlib errors.Unwrap from Go version 1.17.
|
||||
func (err *Error) Unwrap() error {
|
||||
return err.Next()
|
||||
}
|
||||
|
||||
// Equal reports whether current error `err` equals to error `target`.
|
||||
// Please note that, in default comparison for `Error`,
|
||||
// the errors are considered the same if both the `code` and `text` of them are the same.
|
||||
@ -132,19 +127,19 @@ func (err *Error) Equal(target error) bool {
|
||||
}
|
||||
|
||||
// Is reports whether current error `err` has error `target` in its chaining errors.
|
||||
// It is just for implements for stdlib errors.Unwrap from Go version 1.17.
|
||||
// It is just for implements for stdlib errors.Is from Go version 1.17.
|
||||
func (err *Error) Is(target error) bool {
|
||||
if Equal(err, target) {
|
||||
return true
|
||||
}
|
||||
nextErr := err.Next()
|
||||
nextErr := err.Unwrap()
|
||||
if nextErr == nil {
|
||||
return false
|
||||
}
|
||||
if Equal(nextErr, target) {
|
||||
return true
|
||||
}
|
||||
if e, ok := nextErr.(iIs); ok {
|
||||
if e, ok := nextErr.(IIs); ok {
|
||||
return e.Is(target)
|
||||
}
|
||||
return false
|
||||
|
||||
@ -17,7 +17,7 @@ func (err *Error) Code() gcode.Code {
|
||||
return gcode.CodeNil
|
||||
}
|
||||
if err.code == gcode.CodeNil {
|
||||
return Code(err.Next())
|
||||
return Code(err.Unwrap())
|
||||
}
|
||||
return err.code
|
||||
}
|
||||
|
||||
@ -1,57 +0,0 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gerror
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
)
|
||||
|
||||
// iIs is the interface for Is feature.
|
||||
type iIs interface {
|
||||
Is(target error) bool
|
||||
}
|
||||
|
||||
// iEqual is the interface for Equal feature.
|
||||
type iEqual interface {
|
||||
Equal(target error) bool
|
||||
}
|
||||
|
||||
// iCode is the interface for Code feature.
|
||||
type iCode interface {
|
||||
Error() string
|
||||
Code() gcode.Code
|
||||
}
|
||||
|
||||
// iStack is the interface for Stack feature.
|
||||
type iStack interface {
|
||||
Error() string
|
||||
Stack() string
|
||||
}
|
||||
|
||||
// iCause is the interface for Cause feature.
|
||||
type iCause interface {
|
||||
Error() string
|
||||
Cause() error
|
||||
}
|
||||
|
||||
// iCurrent is the interface for Current feature.
|
||||
type iCurrent interface {
|
||||
Error() string
|
||||
Current() error
|
||||
}
|
||||
|
||||
// iNext is the interface for Next feature.
|
||||
type iNext interface {
|
||||
Error() string
|
||||
Next() error
|
||||
}
|
||||
|
||||
// iUnwrap is the interface for Unwrap feature.
|
||||
type iUnwrap interface {
|
||||
Error() string
|
||||
Unwrap() error
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gerror
|
||||
|
||||
import "runtime"
|
||||
|
||||
// stack represents a stack of program counters.
|
||||
type stack []uintptr
|
||||
|
||||
const (
|
||||
// maxStackDepth marks the max stack depth for error back traces.
|
||||
maxStackDepth = 32
|
||||
)
|
||||
|
||||
// callers returns the stack callers.
|
||||
// Note that it here just retrieves the caller memory address array not the caller information.
|
||||
func callers(skip ...int) stack {
|
||||
var (
|
||||
pcs [maxStackDepth]uintptr
|
||||
n = 3
|
||||
)
|
||||
if len(skip) > 0 {
|
||||
n += skip[0]
|
||||
}
|
||||
return pcs[:runtime.Callers(n, pcs[:])]
|
||||
}
|
||||
@ -237,24 +237,6 @@ func Test_Current(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Next(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
err := errors.New("1")
|
||||
err = gerror.Wrap(err, "2")
|
||||
err = gerror.Wrap(err, "3")
|
||||
t.Assert(err.Error(), "3: 2: 1")
|
||||
|
||||
err = gerror.Next(err)
|
||||
t.Assert(err.Error(), "2: 1")
|
||||
|
||||
err = gerror.Next(err)
|
||||
t.Assert(err.Error(), "1")
|
||||
|
||||
err = gerror.Next(err)
|
||||
t.AssertNil(err)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Unwrap(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
err := errors.New("1")
|
||||
@ -381,3 +363,25 @@ func Test_Is(t *testing.T) {
|
||||
t.Assert(gerror.Is(err2, err1), true)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_HashError(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
err1 := errors.New("1")
|
||||
err2 := gerror.Wrap(err1, "2")
|
||||
err2 = gerror.Wrap(err2, "3")
|
||||
t.Assert(gerror.HasError(err2, err1), true)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_HashCode(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
err1 := errors.New("1")
|
||||
err2 := gerror.WrapCode(gcode.CodeNotAuthorized, err1, "2")
|
||||
err3 := gerror.Wrap(err2, "3")
|
||||
err4 := gerror.Wrap(err3, "4")
|
||||
t.Assert(gerror.HasCode(err1, gcode.CodeNotAuthorized), false)
|
||||
t.Assert(gerror.HasCode(err2, gcode.CodeNotAuthorized), true)
|
||||
t.Assert(gerror.HasCode(err3, gcode.CodeNotAuthorized), true)
|
||||
t.Assert(gerror.HasCode(err4, gcode.CodeNotAuthorized), true)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user