67 lines
1.3 KiB
Go
67 lines
1.3 KiB
Go
package errx
|
|
|
|
// Package `errx` named like this to not confuse with built-in `errors` package.
|
|
|
|
import "errors"
|
|
|
|
type detailedError struct {
|
|
error
|
|
details []any
|
|
}
|
|
|
|
func (e *detailedError) Unwrap() error {
|
|
return e.error
|
|
}
|
|
|
|
func (e *detailedError) Details() []any {
|
|
return e.details
|
|
}
|
|
|
|
// WithDetails creates new error value with embedded details
|
|
func WithDetails(err error, details ...any) error {
|
|
derr := &detailedError{}
|
|
if errors.As(err, &derr) {
|
|
derr.details = append(derr.details, details...)
|
|
return err
|
|
}
|
|
|
|
return &detailedError{
|
|
error: err,
|
|
details: details,
|
|
}
|
|
}
|
|
|
|
// Details will extract details array from error
|
|
func Details(err error) []any {
|
|
if err == nil {
|
|
return nil
|
|
}
|
|
|
|
// detailedError on top level of errors chain
|
|
if derr, ok := err.(interface{ Details() []any }); ok {
|
|
return derr.Details()
|
|
}
|
|
|
|
// detailed error were wrapped into another error, and we need to dig it up
|
|
derr := &detailedError{}
|
|
if errors.As(err, &derr) {
|
|
return derr.Details()
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// LookupDetails will find some specific details by its type
|
|
// NOTE: I'm not sure it's good idea or expected behaviour for function named Lookup
|
|
func LookupDetails[T any](err error) T {
|
|
var empty T
|
|
|
|
for _, d := range Details(err) {
|
|
if v, ok := d.(T); ok {
|
|
return v
|
|
}
|
|
}
|
|
|
|
return empty
|
|
}
|