package nstd
import (
"reflect"
"unique"
)
func Error (text string ) error {
return errorString {unique .Make (text )}
}
type errorString struct {
s unique .Handle [string ]
}
func (e errorString ) Error () string {
return e .s .Value ()
}
var errorType = reflect .TypeOf ((*error )(nil )).Elem ()
func TrackError (err , target error ) bool {
if err == nil || target == nil {
return err == target
}
return trackError (err , target )
}
func trackError(err , target error ) bool {
for {
if x , ok := err .(interface { Is (error ) bool }); ok && x .Is (target ) {
return true
}
if err == target {
tt := reflect .TypeOf (target )
if tt .Kind () == reflect .Pointer && tt .Elem ().Size () == 0 {
panic ("target should not be a pointer pointing to a zero-size value" )
}
return true
}
errValue := reflect .ValueOf (err )
errType := errValue .Type ()
if errType .Kind () == reflect .Pointer && errType .Elem ().Implements (errorType ) && !errValue .IsNil () {
if trackError (errValue .Elem ().Interface ().(error ), 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 trackError (err , target ) {
return true
}
}
return false
default :
return false
}
}
}
func TrackErrorOf [ErrorType error ](err error , _ ...ErrorType ) *ErrorType {
if err == nil {
return nil
}
var target = new (ErrorType )
var targetValue = reflect .ValueOf (target )
if n , value := trackErrorOf (err , target , targetValue ); n != 0 {
if n != 1 {
targetValue .Elem ().Set (value )
}
return target
}
return nil
}
func trackErrorOf(err error , target any , targetValue reflect .Value ) (int , reflect .Value ) {
var Type = targetValue .Type ().Elem ()
var info = targetInfo {
value : target ,
reflectValue : targetValue ,
reflectType : Type ,
}
if trackOf (err , &info ) {
return 1 , reflect .Value {}
}
if Type .Kind () == reflect .Pointer {
Type = Type .Elem ()
if Type .Implements (errorType ) {
Value := reflect .New (Type )
info = targetInfo {
value : Value .Interface (),
reflectValue : Value ,
reflectType : Type ,
}
if trackOf (err , &info ) {
return 2 , Value
}
}
} else if Type .Kind () != reflect .Interface {
Type = reflect .PointerTo (Type )
Value := reflect .New (Type )
info = targetInfo {
value : Value .Interface (),
reflectValue : Value ,
reflectType : Type ,
}
if trackOf (err , &info ) {
return 3 , Value .Elem ().Elem ()
}
}
return 0 , reflect .Value {}
}
type targetInfo struct {
value any
reflectValue reflect .Value
reflectType reflect .Type
}
func trackOf(err error , info *targetInfo ) bool {
for {
if x , ok := err .(interface { As (any ) bool }); ok && x .As (info .value ) {
return true
}
if reflect .TypeOf (err ).AssignableTo (info .reflectType ) {
info .reflectValue .Elem ().Set (reflect .ValueOf (err ))
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 trackOf (err , info ) {
return true
}
}
return false
default :
return false
}
}
}
The pages are generated with Golds v0.7.9-preview . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .