github.com/viant/toolbox@v0.34.5/function_util.go (about) 1 package toolbox 2 3 import ( 4 "fmt" 5 "reflect" 6 "strings" 7 ) 8 9 //GetFunction returns function for provided owner and name, or error 10 func GetFunction(owner interface{}, name string) (interface{}, error) { 11 if owner == nil { 12 return nil, fmt.Errorf("failed to lookup %v on %T, owner was nil", name, owner) 13 } 14 var ownerType = reflect.TypeOf(owner) 15 var method, has = ownerType.MethodByName(name) 16 if !has { 17 var available = make([]string, 0) 18 for i := 0; i < ownerType.NumMethod(); i++ { 19 available = append(available, ownerType.Method(i).Name) 20 } 21 return nil, fmt.Errorf("failed to lookup %T.%v, available:[%v]", owner, name, strings.Join(available, ",")) 22 } 23 return reflect.ValueOf(owner).MethodByName(method.Name).Interface(), nil 24 } 25 26 //CallFunction calls passed in function with provided parameters,it returns a function result. 27 func CallFunction(function interface{}, parameters ...interface{}) []interface{} { 28 AssertKind(function, reflect.Func, "function") 29 var functionParameters = make([]reflect.Value, 0) 30 ProcessSlice(parameters, func(item interface{}) bool { 31 functionParameters = append(functionParameters, reflect.ValueOf(item)) 32 return true 33 }) 34 35 functionValue := reflect.ValueOf(function) 36 var resultValues = functionValue.Call(functionParameters) 37 var result = make([]interface{}, len(resultValues)) 38 for i, resultValue := range resultValues { 39 result[i] = resultValue.Interface() 40 } 41 return result 42 } 43 44 //AsCompatibleFunctionParameters takes incompatible function parameters and converts then into provided function signature compatible 45 func AsCompatibleFunctionParameters(function interface{}, parameters []interface{}) ([]interface{}, error) { 46 return AsFunctionParameters(function, parameters, map[string]interface{}{}) 47 } 48 49 //AsFunctionParameters takes incompatible function parameters and converts then into provided function signature compatible 50 func AsFunctionParameters(function interface{}, parameters []interface{}, parametersKV map[string]interface{}) ([]interface{}, error) { 51 AssertKind(function, reflect.Func, "function") 52 functionValue := reflect.ValueOf(function) 53 funcSignature := GetFuncSignature(function) 54 actualMethodSignatureLength := len(funcSignature) 55 converter := Converter{} 56 if actualMethodSignatureLength != len(parameters) { 57 return nil, fmt.Errorf("invalid number of parameters wanted: [%T], had: %v", function, len(parameters)) 58 } 59 var functionParameters = make([]interface{}, 0) 60 for i, parameterValue := range parameters { 61 isStruct := IsStruct(funcSignature[i]) 62 if isStruct && parameterValue == nil { 63 parameterValue = make(map[string]interface{}) 64 } 65 reflectValue := reflect.ValueOf(parameterValue) 66 if !isStruct { 67 if parameterValue == nil { 68 return nil, fmt.Errorf("parameter[%v] was empty", i) 69 } 70 if reflectValue.Kind() == reflect.Slice && funcSignature[i].Kind() != reflectValue.Kind() { 71 return nil, fmt.Errorf("incompatible types expected: %v, but had %v", funcSignature[i].Kind(), reflectValue.Kind()) 72 } else if !reflectValue.IsValid() { 73 if funcSignature[i].Kind() == reflect.Slice { 74 parameterValue = reflect.New(funcSignature[i]).Interface() 75 reflectValue = reflect.ValueOf(parameterValue) 76 } 77 } 78 } 79 if reflectValue.Type() != funcSignature[i] { 80 newValuePointer := reflect.New(funcSignature[i]) 81 var err error 82 if IsStruct(funcSignature[i]) && !(IsStruct(parameterValue) || IsMap(parameterValue)) { 83 err = converter.AssignConverted(newValuePointer.Interface(), parametersKV) 84 } else { 85 err = converter.AssignConverted(newValuePointer.Interface(), parameterValue) 86 } 87 if err != nil { 88 return nil, fmt.Errorf("failed to assign convert %v to %v due to %v", parametersKV, newValuePointer.Interface(), err) 89 } 90 reflectValue = newValuePointer.Elem() 91 } 92 if functionValue.Type().IsVariadic() && funcSignature[i].Kind() == reflect.Slice && i+1 == len(funcSignature) { 93 ProcessSlice(reflectValue.Interface(), func(item interface{}) bool { 94 functionParameters = append(functionParameters, item) 95 return true 96 }) 97 } else { 98 functionParameters = append(functionParameters, reflectValue.Interface()) 99 } 100 } 101 return functionParameters, nil 102 } 103 104 //BuildFunctionParameters builds function parameters provided in the parameterValues. 105 // Parameters value will be converted if needed to expected by the function signature type. It returns function parameters , or error 106 func BuildFunctionParameters(function interface{}, parameters []string, parameterValues map[string]interface{}) ([]interface{}, error) { 107 var functionParameters = make([]interface{}, 0) 108 for _, name := range parameters { 109 functionParameters = append(functionParameters, parameterValues[name]) 110 } 111 return AsFunctionParameters(function, functionParameters, parameterValues) 112 } 113 114 //GetFuncSignature returns a function signature 115 func GetFuncSignature(function interface{}) []reflect.Type { 116 AssertKind(function, reflect.Func, "function") 117 functionValue := reflect.ValueOf(function) 118 var result = make([]reflect.Type, 0) 119 functionType := functionValue.Type() 120 for i := 0; i < functionType.NumIn(); i++ { 121 result = append(result, functionType.In(i)) 122 } 123 return result 124 }