github.com/pachyderm/pachyderm@v1.13.4/src/client/pkg/errors/as.go (about)

     1  package errors
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  
     7  	"github.com/pkg/errors"
     8  )
     9  
    10  var errorType = reflect.TypeOf((*error)(nil)).Elem()
    11  
    12  func tryAs(err error, targetVal reflect.Value) bool {
    13  	e := targetVal.Type().Elem()
    14  	if e.Kind() == reflect.Interface || e.Implements(errorType) {
    15  		return errors.As(err, targetVal.Interface())
    16  	}
    17  	return false
    18  }
    19  
    20  // As finds the first error in err's chain that matches the target's type, and
    21  // if so, sets target to that error value and returns true.
    22  // As is a wrapper for the underlying errors.As function, which may panic or
    23  // return unexpected results based on how err was constructed (with or without
    24  // a pointer).  This works by inspecting the type of target and attempting
    25  // multiple errors.As calls if necessary.
    26  func As(err error, target interface{}) bool {
    27  	v := reflect.ValueOf(target)
    28  
    29  	switch v.Kind() {
    30  	case reflect.Ptr:
    31  		// Attempt unwrapping a nested pointer
    32  		if v.Elem().Kind() == reflect.Ptr && tryAs(err, v.Elem()) {
    33  			return true
    34  		}
    35  
    36  		// Attempt wrapping with an additional pointer
    37  		vp := reflect.New(v.Type())
    38  		if tryAs(err, vp) {
    39  			v.Elem().Set(vp.Elem().Elem())
    40  			return true
    41  		}
    42  
    43  		// Attempt the passed target as-is
    44  		return tryAs(err, v)
    45  	}
    46  	panic(fmt.Sprintf("unexpected target type: %v, errors.As must be passed a pointer target", v.Kind()))
    47  }