github.com/mattn/anko@v0.1.10/vm/vmConvertToX.go (about) 1 package vm 2 3 import ( 4 "context" 5 "fmt" 6 "reflect" 7 ) 8 9 // reflectValueSlicetoInterfaceSlice convert from a slice of reflect.Value to a interface slice 10 // returned in normal reflect.Value form 11 func reflectValueSlicetoInterfaceSlice(valueSlice []reflect.Value) reflect.Value { 12 interfaceSlice := make([]interface{}, 0, len(valueSlice)) 13 for _, value := range valueSlice { 14 if value.Kind() == reflect.Interface && !value.IsNil() { 15 value = value.Elem() 16 } 17 if value.CanInterface() { 18 interfaceSlice = append(interfaceSlice, value.Interface()) 19 } else { 20 interfaceSlice = append(interfaceSlice, nil) 21 } 22 } 23 return reflect.ValueOf(interfaceSlice) 24 } 25 26 // convertReflectValueToType trys to covert the reflect.Value to the reflect.Type 27 // if it can not, it returns the original rv and an error 28 func convertReflectValueToType(rv reflect.Value, rt reflect.Type) (reflect.Value, error) { 29 if rt == interfaceType || rv.Type() == rt { 30 // if reflect.Type is interface or the types match, return the provided reflect.Value 31 return rv, nil 32 } 33 if rv.Type().ConvertibleTo(rt) { 34 // if reflect can covert, do that conversion and return 35 return rv.Convert(rt), nil 36 } 37 if (rv.Kind() == reflect.Slice || rv.Kind() == reflect.Array) && 38 (rt.Kind() == reflect.Slice || rt.Kind() == reflect.Array) { 39 // covert slice or array 40 return convertSliceOrArray(rv, rt) 41 } 42 if rv.Kind() == rt.Kind() { 43 // kind matches 44 switch rv.Kind() { 45 case reflect.Map: 46 // convert map 47 return convertMap(rv, rt) 48 case reflect.Func: 49 // for runVMFunction conversions, call convertVMFunctionToType 50 return convertVMFunctionToType(rv, rt) 51 case reflect.Ptr: 52 // both rv and rt are pointers, convert what they are pointing to 53 value, err := convertReflectValueToType(rv.Elem(), rt.Elem()) 54 if err != nil { 55 return rv, err 56 } 57 // need to make a new value to be able to set it 58 ptrV, err := makeValue(rt) 59 if err != nil { 60 return rv, err 61 } 62 // set value and return new pointer 63 ptrV.Elem().Set(value) 64 return ptrV, nil 65 } 66 } 67 if rv.Type() == interfaceType { 68 if rv.IsNil() { 69 // return nil of correct type 70 return reflect.Zero(rt), nil 71 } 72 // try to convert the element 73 return convertReflectValueToType(rv.Elem(), rt) 74 } 75 76 if rv.Type() == stringType { 77 if rt == byteType { 78 aString := rv.String() 79 if len(aString) < 1 { 80 return reflect.Zero(rt), nil 81 } 82 if len(aString) > 1 { 83 return rv, errInvalidTypeConversion 84 } 85 return reflect.ValueOf(aString[0]), nil 86 } 87 if rt == runeType { 88 aString := rv.String() 89 if len(aString) < 1 { 90 return reflect.Zero(rt), nil 91 } 92 if len(aString) > 1 { 93 return rv, errInvalidTypeConversion 94 } 95 return reflect.ValueOf(rune(aString[0])), nil 96 } 97 } 98 99 // TODO: need to handle the case where either rv or rt are a pointer but not both 100 101 return rv, errInvalidTypeConversion 102 } 103 104 // convertSliceOrArray trys to covert the reflect.Value slice or array to the slice or array reflect.Type 105 func convertSliceOrArray(rv reflect.Value, rt reflect.Type) (reflect.Value, error) { 106 rtElemType := rt.Elem() 107 108 // try to covert elements to new slice/array 109 var value reflect.Value 110 if rt.Kind() == reflect.Slice { 111 // make slice 112 value = reflect.MakeSlice(rt, rv.Len(), rv.Len()) 113 } else { 114 // make array 115 value = reflect.New(rt).Elem() 116 } 117 118 var err error 119 var v reflect.Value 120 for i := 0; i < rv.Len(); i++ { 121 v, err = convertReflectValueToType(rv.Index(i), rtElemType) 122 if err != nil { 123 return rv, err 124 } 125 value.Index(i).Set(v) 126 } 127 128 // return new converted slice or array 129 return value, nil 130 } 131 132 // convertVMFunctionToType is for translating a runVMFunction into the correct type 133 // so it can be passed to a Go function argument with the correct static types 134 // it creates a translate function runVMConvertFunction 135 func convertVMFunctionToType(rv reflect.Value, rt reflect.Type) (reflect.Value, error) { 136 // only translates runVMFunction type 137 if !checkIfRunVMFunction(rv.Type()) { 138 return rv, errInvalidTypeConversion 139 } 140 141 // create runVMConvertFunction to match reflect.Type 142 // this function is being called by the Go function 143 runVMConvertFunction := func(in []reflect.Value) []reflect.Value { 144 // note: this function is being called by another reflect Call 145 // only way to pass along any errors is by panic 146 147 // make the reflect.Value slice of each of the VM reflect.Value 148 args := make([]reflect.Value, 0, rt.NumIn()+1) 149 // for runVMFunction first arg is always context 150 // TOFIX: use normal context 151 args = append(args, reflect.ValueOf(context.Background())) 152 for i := 0; i < rt.NumIn(); i++ { 153 // have to do the double reflect.ValueOf that runVMFunction expects 154 args = append(args, reflect.ValueOf(in[i])) 155 } 156 157 // Call runVMFunction 158 rvs := rv.Call(args) 159 160 // call processCallReturnValues to process runVMFunction return values 161 // returns normal VM reflect.Value form 162 rv, err := processCallReturnValues(rvs, true, false) 163 if err != nil { 164 panic(err) 165 } 166 167 if rt.NumOut() < 1 { 168 // Go function does not want any return values, so give it none 169 return []reflect.Value{} 170 } 171 if rt.NumOut() < 2 { 172 // Go function wants one return value 173 // will try to covert to reflect.Value correct type and return 174 rv, err = convertReflectValueToType(rv, rt.Out(0)) 175 if err != nil { 176 panic("function wants return type " + rt.Out(0).String() + " but received type " + rv.Type().String()) 177 } 178 return []reflect.Value{rv} 179 } 180 181 // Go function wants more than one return value 182 // make sure we have a slice/array with enought values 183 184 if rv.Kind() != reflect.Slice && rv.Kind() != reflect.Array { 185 panic(fmt.Sprintf("function wants %v return values but received %v", rt.NumOut(), rv.Kind().String())) 186 } 187 if rv.Len() < rt.NumOut() { 188 panic(fmt.Sprintf("function wants %v return values but received %v values", rt.NumOut(), rv.Len())) 189 } 190 191 // try to covert each value in slice to wanted type and put into a reflect.Value slice 192 rvs = make([]reflect.Value, rt.NumOut()) 193 for i := 0; i < rv.Len(); i++ { 194 rvs[i], err = convertReflectValueToType(rv.Index(i), rt.Out(i)) 195 if err != nil { 196 panic("function wants return type " + rt.Out(i).String() + " but received type " + rvs[i].Type().String()) 197 } 198 } 199 200 // return created reflect.Value slice 201 return rvs 202 } 203 204 // make the reflect.Value function that calls runVMConvertFunction 205 return reflect.MakeFunc(rt, runVMConvertFunction), nil 206 }