Files
galaxy-game/pkg/error/class.go
T
2026-03-16 19:52:02 +02:00

112 lines
3.1 KiB
Go

package error
import "errors"
// Class describes a top-level operational error class that can be used by
// higher layers to route failures to the appropriate UI or transport handler.
type Class string
const (
// ClassConnection marks connectivity and transport failures talking to remote services.
ClassConnection Class = "connection"
// ClassStorage marks local persistence and filesystem related failures.
ClassStorage Class = "storage"
// ClassService marks remote service contract and processing failures.
ClassService Class = "service"
)
// ClassifiedError wraps another error with a top-level error class.
//
// The wrapped error remains available through Unwrap so existing callers may
// continue using errors.Is or errors.As against the original cause.
type ClassifiedError struct {
class Class
err error
}
// Error returns either the wrapped error text or, when no wrapped error is available,
// the textual representation of the class itself.
func (e *ClassifiedError) Error() string {
if e == nil {
return ""
}
if e.err != nil {
return e.err.Error()
}
return string(e.class)
}
// Unwrap exposes the wrapped cause for standard Go error inspection.
func (e *ClassifiedError) Unwrap() error {
if e == nil {
return nil
}
return e.err
}
// Class returns the top-level class recorded on this error.
func (e *ClassifiedError) Class() Class {
if e == nil {
return ""
}
return e.class
}
// Is reports class equality so errors.Is(err, ErrConnection) style checks remain possible.
func (e *ClassifiedError) Is(target error) bool {
t, ok := target.(*ClassifiedError)
if !ok {
return false
}
return e.class != "" && e.class == t.class
}
var (
// ErrConnection is a class sentinel for connection related failures.
ErrConnection = &ClassifiedError{class: ClassConnection}
// ErrStorage is a class sentinel for storage related failures.
ErrStorage = &ClassifiedError{class: ClassStorage}
// ErrService is a class sentinel for service related failures.
ErrService = &ClassifiedError{class: ClassService}
)
// WrapConnection wraps err with the connection class unless it is already classified.
func WrapConnection(err error) error {
return wrapClass(ClassConnection, err)
}
// WrapStorage wraps err with the storage class unless it is already classified.
func WrapStorage(err error) error {
return wrapClass(ClassStorage, err)
}
// WrapService wraps err with the service class unless it is already classified.
func WrapService(err error) error {
return wrapClass(ClassService, err)
}
// IsConnection reports whether err is classified as a connection failure.
func IsConnection(err error) bool {
return errors.Is(err, ErrConnection)
}
// IsStorage reports whether err is classified as a storage failure.
func IsStorage(err error) bool {
return errors.Is(err, ErrStorage)
}
// IsService reports whether err is classified as a service failure.
func IsService(err error) bool {
return errors.Is(err, ErrService)
}
func wrapClass(class Class, err error) error {
if err == nil {
return nil
}
if existing, ok := errors.AsType[*ClassifiedError](err); ok && existing.class == class {
return err
}
return &ClassifiedError{class: class, err: err}
}