Files
core/errors/utils.go
T
2025-04-25 11:20:31 +03:00

128 lines
2.4 KiB
Go

package errors
import (
"reflect"
)
func Wrap(err error, message string) error {
return &UniverseErrorImpl{
msg: message,
cause: err,
stack: CaptureStackIfEnabled(),
}
}
func Get[T *any](err error, field string) T {
if err == nil {
return nil
}
var uerr UniverseError
if As(err, &uerr) {
value := uerr.GetAny(field)
if value, ok := value.(T); ok {
return value
}
}
return nil
}
func Unwrap(err error) error {
u, ok := err.(interface {
Unwrap() error
})
if !ok {
return nil
}
return u.Unwrap()
}
func Is(err, target error) bool {
if err == nil || target == nil {
return err == target
}
isComparable := reflect.TypeOf(target).Comparable()
return is(err, target, isComparable)
}
func is(err, target error, targetComparable bool) bool {
for {
if targetComparable && err == target {
return true
}
if x, ok := err.(interface{ Is(error) bool }); ok && x.Is(target) {
return true
}
switch x := err.(type) {
case interface{ Unwrap() error }:
err = x.Unwrap()
if err == nil {
return false
}
case interface{ Unwrap() []error }:
for _, err := range x.Unwrap() {
if is(err, target, targetComparable) {
return true
}
}
return false
default:
return false
}
}
}
func As(err error, target any) bool {
if err == nil {
return false
}
if target == nil {
panic("errors: target cannot be nil")
}
val := reflect.ValueOf(target)
typ := val.Type()
if typ.Kind() != reflect.Ptr || val.IsNil() {
panic("errors: target must be a non-nil pointer")
}
targetType := typ.Elem()
if targetType.Kind() != reflect.Interface && !targetType.Implements(errorType) {
panic("errors: *target must be interface or implement error")
}
return as(err, target, val, targetType)
}
func as(err error, target any, targetVal reflect.Value, targetType reflect.Type) bool {
for {
if reflect.TypeOf(err).AssignableTo(targetType) {
targetVal.Elem().Set(reflect.ValueOf(err))
return true
}
if x, ok := err.(interface{ As(any) bool }); ok && x.As(target) {
return true
}
switch x := err.(type) {
case interface{ Unwrap() error }:
err = x.Unwrap()
if err == nil {
return false
}
case interface{ Unwrap() []error }:
for _, err := range x.Unwrap() {
if err == nil {
continue
}
if as(err, target, targetVal, targetType) {
return true
}
}
return false
default:
return false
}
}
}
var errorType = reflect.TypeOf((*error)(nil)).Elem()