gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

standard.go (3928B)


      1 package errors
      2 
      3 import (
      4 	"errors"
      5 	"reflect"
      6 	_ "unsafe"
      7 
      8 	"codeberg.org/gruf/go-bitutil"
      9 )
     10 
     11 // errtype is a ptr to the error interface type.
     12 var errtype = reflect.TypeOf((*error)(nil)).Elem()
     13 
     14 // Comparable is functionally equivalent to calling errors.Is() on multiple errors (up to a max of 64).
     15 func Comparable(err error, targets ...error) bool {
     16 	var flags bitutil.Flags64
     17 
     18 	// Flags only has 64 bit-slots
     19 	if len(targets) > 64 {
     20 		panic("too many targets")
     21 	}
     22 
     23 	for i := 0; i < len(targets); {
     24 		if targets[i] == nil {
     25 			if err == nil {
     26 				return true
     27 			}
     28 
     29 			// Drop nil targets from slice.
     30 			copy(targets[i:], targets[i+1:])
     31 			targets = targets[:len(targets)-1]
     32 			continue
     33 		}
     34 
     35 		// Check if this error is directly comparable
     36 		if reflect.TypeOf(targets[i]).Comparable() {
     37 			flags = flags.Set(uint8(i))
     38 		}
     39 
     40 		i++
     41 	}
     42 
     43 	for err != nil {
     44 		// Check if this layer supports .Is interface
     45 		is, ok := err.(interface{ Is(error) bool })
     46 
     47 		if !ok {
     48 			// Error does not support interface
     49 			//
     50 			// Only try perform direct compare
     51 			for i := 0; i < len(targets); i++ {
     52 				// Try directly compare errors
     53 				if flags.Get(uint8(i)) &&
     54 					err == targets[i] {
     55 					return true
     56 				}
     57 			}
     58 		} else {
     59 			// Error supports the .Is interface
     60 			//
     61 			// Perform direct compare AND .Is()
     62 			for i := 0; i < len(targets); i++ {
     63 				if (flags.Get(uint8(i)) &&
     64 					err == targets[i]) ||
     65 					is.Is(targets[i]) {
     66 					return true
     67 				}
     68 			}
     69 		}
     70 
     71 		// Unwrap to next layer
     72 		err = errors.Unwrap(err)
     73 	}
     74 
     75 	return false
     76 }
     77 
     78 // Assignable is functionally equivalent to calling errors.As() on multiple errors,
     79 // except that it only checks assignability as opposed to setting the target.
     80 func Assignable(err error, targets ...error) bool {
     81 	if err == nil {
     82 		// Fastest case.
     83 		return false
     84 	}
     85 
     86 	for i := 0; i < len(targets); {
     87 		if targets[i] == nil {
     88 			// Drop nil targets from slice.
     89 			copy(targets[i:], targets[i+1:])
     90 			targets = targets[:len(targets)-1]
     91 			continue
     92 		}
     93 		i++
     94 	}
     95 
     96 	for err != nil {
     97 		// Check if this layer supports .As interface
     98 		as, ok := err.(interface{ As(any) bool })
     99 
    100 		// Get reflected err type.
    101 		te := reflect.TypeOf(err)
    102 
    103 		if !ok {
    104 			// Error does not support interface.
    105 			//
    106 			// Check assignability using reflection.
    107 			for i := 0; i < len(targets); i++ {
    108 				tt := reflect.TypeOf(targets[i])
    109 				if te.AssignableTo(tt) {
    110 					return true
    111 				}
    112 			}
    113 		} else {
    114 			// Error supports the .As interface.
    115 			//
    116 			// Check using .As() and reflection.
    117 			for i := 0; i < len(targets); i++ {
    118 				if as.As(targets[i]) {
    119 					return true
    120 				} else if tt := reflect.TypeOf(targets[i]); // nocollapse
    121 				te.AssignableTo(tt) {
    122 					return true
    123 				}
    124 			}
    125 		}
    126 
    127 		// Unwrap to next layer.
    128 		err = errors.Unwrap(err)
    129 	}
    130 
    131 	return false
    132 }
    133 
    134 // As finds the first error in err's tree that matches target, and if one is found, sets
    135 // target to that error value and returns true. Otherwise, it returns false.
    136 //
    137 // The tree consists of err itself, followed by the errors obtained by repeatedly
    138 // calling Unwrap. When err wraps multiple errors, As examines err followed by a
    139 // depth-first traversal of its children.
    140 //
    141 // An error matches target if the error's concrete value is assignable to the value
    142 // pointed to by target, or if the error has a method As(interface{}) bool such that
    143 // As(target) returns true. In the latter case, the As method is responsible for
    144 // setting target.
    145 //
    146 // An error type might provide an As method so it can be treated as if it were a
    147 // different error type.
    148 //
    149 // As panics if target is not a non-nil pointer to either a type that implements
    150 // error, or to any interface type.
    151 //
    152 //go:linkname As errors.As
    153 func As(err error, target any) bool
    154 
    155 // Unwrap returns the result of calling the Unwrap method on err, if err's
    156 // type contains an Unwrap method returning error. Otherwise, Unwrap returns nil.
    157 //
    158 //go:linkname Unwrap errors.Unwrap
    159 func Unwrap(err error) error