You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

193 lines
4.6 KiB

package errs
import (
"core/errs/stack"
"fmt"
"regexp"
)
const (
// errCodePattern is the regular expression that defines a valid error code format.
// The error code can optionally have a module, which is separated by "::".
// The valid characters are alphanumeric characters and the symbols ":-_".
errCodePattern string = "^[a-zA-Z0-9._-]+(::[a-zA-Z0-9._-]+)?$"
)
const (
// ModuleSeparator is the separator used between the module and value parts of the error code.
ModuleSeparator string = "::"
)
// Module configuration
const moduleName = "core.errs" + ModuleSeparator
// Error messages for internal use
const (
errNilWrapMsg string = "error trying to wrap % into a nil error"
errNilCauseMsg string = "error trying to wrap % into a nil cause"
)
// Standard error codes for common error scenarios
const (
CodePanicError string = "panic"
CodeMultiError string = "multiple-errors"
CodeParamError string = "Param"
CodeParamNilError string = "Param-nil"
CodeParamOutOfRangeError string = "Param-out-of-range"
)
// G provides a global access point for common errors and information
// This struct combines documentation links and pre-initialized error instances
var (
G = struct {
InfoHelp,
InfoLink string
ErrParam,
ErrParamNil,
ErrParamOutOfRange,
ErrInvalidError,
ErrInvalidNilError,
ErrUnknownPanicError,
ErrInvalidErrCode ErrCode
}{
InfoLink: "https://git.activething.com/go/active",
InfoHelp: "https://doc.activething.com/go/active",
ErrParam: ErrCode(CodeParamError),
ErrParamNil: ErrCode(CodeParamNilError),
ErrParamOutOfRange: ErrCode(CodeParamOutOfRangeError),
ErrUnknownPanicError: ErrCode(moduleName + "unknown-panic-error"),
ErrInvalidNilError: ErrCode(moduleName + "invalid-nil-error"),
ErrInvalidError: ErrCode(moduleName + "invalid-error"),
ErrInvalidErrCode: ErrCode(moduleName + "invalid-err-code"),
}
// g contains private package-level variables
g = struct {
panicErrNil *ErrPanic
codeValidator *regexp.Regexp
}{
panicErrNil: NewErrPanic(G.ErrInvalidNilError),
codeValidator: regexp.MustCompile(errCodePattern),
}
)
// ToError converts any value to an error type
// Returns nil if the input is nil
// Converts []error to ErrMulti
// Uses fmt.Errorf for other types
func ToError(err any) error {
if err == nil {
return nil
}
switch e := err.(type) {
case error:
return e
case []error:
if len(e) == 0 {
return nil
}
return NewErrMulti(e...)
default:
return fmt.Errorf("%v", err)
}
}
// PanicRecoveredError creates an error from a recovered panic value
// Returns nil if the recovered value is nil
func PanicRecoveredError(rec any) error {
if rec == nil {
return nil
}
return *NewErrPanic(ToError(rec))
}
// Unwrap provides standard error unwrapping functionality
// Implements the unwrap interface for error chains
func Unwrap(err error) error {
if err == nil {
return nil
}
if cs, is := err.(Unwrapper); is {
return cs.Unwrap()
}
return nil
}
// UnwrapCause retrieves the root cause of an error chain
// Traverses the error chain looking for Causer implementation
func UnwrapCause(err error) error {
e := err
for e != nil {
cs, is := e.(Causer)
if is {
return cs.Cause()
}
e = Unwrap(e)
}
return nil
}
// UnwrapCauses retrieves all causes in an error chain
// Returns a slice of errors representing the cause chain
func UnwrapCauses(err error) []error {
if err == nil {
return nil
}
if al, is := err.(Causers); is {
return al.Causes()
}
var l ErrorList
e := err
for e != nil {
l = append(l, e)
e = Unwrap(e)
}
return l
}
// UnwrapList retrieves all errors in an error chain as an ErrorList
// Handles both UnwrapperList implementations and standard error chains
func UnwrapList(err error) ErrorList {
if err == nil {
return nil
}
if al, is := err.(UnwrapperList); is {
return al.Unwrap()
}
var l ErrorList
e := err
for e != nil {
l = append(l, e)
e = Unwrap(e)
}
return l
}
// UnwrapTrace retrieves the stack trace from an error
func UnwrapTrace(err error) stack.Stack {
return stack.UnwrapStack(err, false)
}
// WrapError combines two errors into a single error, establishing a cause relationship.
// If either error is nil, the non-nil error is returned.
// Otherwise, a new error is returned that has the first error as the cause.
func WrapError(err, cause error) error {
if err == nil {
return cause
}
if cause == nil {
return err
}
return *NewErrWithCause(err, cause)
}
// ValidateCode check if un err code is valid
func ValidateCode(code string) bool {
return g.codeValidator.MatchString(code)
}

Powered by TurnKey Linux.