github.com/insolar/vanilla@v0.0.0-20201023172447-248fdf805322/throw/as.go (about) 1 // Copyright 2020 Insolar Network Ltd. 2 // All rights reserved. 3 // This material is licensed under the Insolar License version 1.0, 4 // available at https://github.com/insolar/assured-ledger/blob/master/LICENSE.md. 5 6 package throw 7 8 import ( 9 "errors" 10 "reflect" 11 ) 12 13 func asDetail(value interface{}, target interface{}) bool { 14 targetType, val := checkAsTarget(target) 15 if value == nil { 16 return false 17 } 18 if reflect.TypeOf(value).AssignableTo(targetType) { 19 val.Elem().Set(reflect.ValueOf(value)) 20 return true 21 } 22 if x, ok := value.(interface{ AsDetail(interface{}) bool }); ok && x.AsDetail(target) { 23 return true 24 } 25 return false 26 } 27 28 func FindDetail(value error, target interface{}) bool { 29 targetType, val := checkAsTarget(target) 30 for value != nil { 31 switch valueType := reflect.TypeOf(value); { 32 case valueType.Kind() == reflect.Ptr: 33 if valueType.Elem().AssignableTo(targetType) { 34 val.Elem().Set(reflect.ValueOf(value).Elem()) 35 return true 36 } 37 case valueType.AssignableTo(targetType): 38 val.Elem().Set(reflect.ValueOf(value)) 39 return true 40 } 41 if x, ok := value.(interface{ As(interface{}) bool }); ok && x.As(target) { 42 return true 43 } 44 if x, ok := value.(interface{ AsDetail(interface{}) bool }); ok && x.AsDetail(target) { 45 return true 46 } 47 value = errors.Unwrap(value) 48 } 49 return false 50 } 51 52 func checkAsTarget(target interface{}) (reflect.Type, reflect.Value) { 53 if target == nil { 54 panic("errors: target cannot be nil") 55 } 56 val := reflect.ValueOf(target) 57 typ := val.Type() 58 if typ.Kind() != reflect.Ptr || val.IsNil() { 59 panic("errors: target must be a non-nil pointer") 60 } 61 targetType := typ.Elem() 62 switch targetType.Kind() { 63 case reflect.Interface, reflect.Struct: 64 return targetType, val 65 default: 66 panic("errors: *target must be interface or struct") 67 } 68 }