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 }