github.com/songzhibin97/gkit@v1.2.13/tools/reflect2value/reflect.go (about) 1 package reflect2value 2 3 import ( 4 "encoding/base64" 5 "encoding/json" 6 "fmt" 7 "reflect" 8 "strings" 9 ) 10 11 var typeOfMap = map[string]reflect.Type{ 12 // basic 13 "bool": reflect.TypeOf(false), 14 15 "int": reflect.TypeOf(int(0)), 16 "int8": reflect.TypeOf(int8(0)), 17 "int16": reflect.TypeOf(int16(0)), 18 "int32": reflect.TypeOf(int32(0)), 19 "int64": reflect.TypeOf(int64(0)), 20 21 "uint": reflect.TypeOf(uint(0)), 22 "uint8": reflect.TypeOf(uint8(0)), 23 "uint16": reflect.TypeOf(uint16(0)), 24 "uint32": reflect.TypeOf(uint32(0)), 25 "uint64": reflect.TypeOf(uint64(0)), 26 27 "float32": reflect.TypeOf(float32(0)), 28 "float64": reflect.TypeOf(float64(0)), 29 30 "string": reflect.TypeOf(string("")), 31 32 // compound 33 34 // slice 35 "[]bool": reflect.TypeOf(make([]bool, 0)), 36 37 //"[]byte": reflect.TypeOf(make([]byte, 0)), 38 //"[]rune": reflect.TypeOf(make([]rune, 0)), 39 40 "[]int": reflect.TypeOf(make([]int, 0)), 41 "[]int8": reflect.TypeOf(make([]int8, 0)), 42 "[]int16": reflect.TypeOf(make([]int16, 0)), 43 "[]int32": reflect.TypeOf(make([]int32, 0)), 44 "[]int64": reflect.TypeOf(make([]int64, 0)), 45 46 "[]uint": reflect.TypeOf(make([]uint, 0)), 47 "[]uint8": reflect.TypeOf(make([]uint8, 0)), 48 "[]uint16": reflect.TypeOf(make([]uint16, 0)), 49 "[]uint32": reflect.TypeOf(make([]uint32, 0)), 50 "[]uint64": reflect.TypeOf(make([]uint64, 0)), 51 52 "[]float32": reflect.TypeOf(make([]float32, 0)), 53 "[]float64": reflect.TypeOf(make([]float64, 0)), 54 55 "[]string": reflect.TypeOf(make([]string, 0)), 56 } 57 58 var typeConversionError = func(argValue interface{}, argTypeStr string) error { 59 return fmt.Errorf("%v is not %v", argValue, argTypeStr) 60 } 61 62 // HumanReadableResults ... 63 func HumanReadableResults(results []reflect.Value) string { 64 if len(results) == 1 { 65 return fmt.Sprintf("%v", results[0].Interface()) 66 } 67 68 readableResults := make([]string, len(results)) 69 for i := 0; i < len(results); i++ { 70 readableResults[i] = fmt.Sprintf("%v", results[i].Interface()) 71 } 72 73 return fmt.Sprintf("[%s]", strings.Join(readableResults, ", ")) 74 } 75 76 // ReflectValue converts interface{} to reflect.Value based on string type 77 func ReflectValue(valueType string, value interface{}) (reflect.Value, error) { 78 if strings.HasPrefix(valueType, "[]") { 79 return reflectValues(valueType, value) 80 } 81 82 return reflectValue(valueType, value) 83 } 84 85 // reflectValue converts interface{} to reflect.Value based on string type 86 // representing a base type (not a slice) 87 func reflectValue(valueType string, value interface{}) (reflect.Value, error) { 88 theType, ok := typeOfMap[valueType] 89 if !ok { 90 return reflect.Value{}, NewErrNonsupportType(valueType) 91 } 92 theValue := reflect.New(theType) 93 94 // Booleans 95 if theType.String() == "bool" { 96 boolValue, err := getBoolValue(theType.String(), value) 97 if err != nil { 98 return reflect.Value{}, err 99 } 100 101 theValue.Elem().SetBool(boolValue) 102 return theValue.Elem(), nil 103 } 104 105 // Integers 106 if strings.HasPrefix(theType.String(), "int") { 107 intValue, err := getIntValue(theType.String(), value) 108 if err != nil { 109 return reflect.Value{}, err 110 } 111 112 theValue.Elem().SetInt(intValue) 113 return theValue.Elem(), err 114 } 115 116 // Unsigned integers 117 if strings.HasPrefix(theType.String(), "uint") { 118 uintValue, err := getUintValue(theType.String(), value) 119 if err != nil { 120 return reflect.Value{}, err 121 } 122 123 theValue.Elem().SetUint(uintValue) 124 return theValue.Elem(), err 125 } 126 127 // Floating point numbers 128 if strings.HasPrefix(theType.String(), "float") { 129 floatValue, err := getFloatValue(theType.String(), value) 130 if err != nil { 131 return reflect.Value{}, err 132 } 133 134 theValue.Elem().SetFloat(floatValue) 135 return theValue.Elem(), err 136 } 137 138 // Strings 139 if theType.String() == "string" { 140 stringValue, err := getStringValue(theType.String(), value) 141 if err != nil { 142 return reflect.Value{}, err 143 } 144 145 theValue.Elem().SetString(stringValue) 146 return theValue.Elem(), nil 147 } 148 149 return reflect.Value{}, NewErrNonsupportType(valueType) 150 } 151 152 // reflectValues converts interface{} to reflect.Value based on string type 153 // representing a slice of values 154 func reflectValues(valueType string, value interface{}) (reflect.Value, error) { 155 theType, ok := typeOfMap[valueType] 156 if !ok { 157 return reflect.Value{}, NewErrNonsupportType(valueType) 158 } 159 160 // For NULL we return an empty slice 161 if value == nil { 162 return reflect.MakeSlice(theType, 0, 0), nil 163 } 164 165 var theValue reflect.Value 166 167 // Booleans 168 if theType.String() == "[]bool" { 169 bools := reflect.ValueOf(value) 170 171 theValue = reflect.MakeSlice(theType, bools.Len(), bools.Len()) 172 for i := 0; i < bools.Len(); i++ { 173 boolValue, err := getBoolValue(strings.Split(theType.String(), "[]")[1], bools.Index(i).Interface()) 174 if err != nil { 175 return reflect.Value{}, err 176 } 177 178 theValue.Index(i).SetBool(boolValue) 179 } 180 181 return theValue, nil 182 } 183 184 // Integers 185 if strings.HasPrefix(theType.String(), "[]int") { 186 ints := reflect.ValueOf(value) 187 188 theValue = reflect.MakeSlice(theType, ints.Len(), ints.Len()) 189 for i := 0; i < ints.Len(); i++ { 190 intValue, err := getIntValue(strings.Split(theType.String(), "[]")[1], ints.Index(i).Interface()) 191 if err != nil { 192 return reflect.Value{}, err 193 } 194 195 theValue.Index(i).SetInt(intValue) 196 } 197 198 return theValue, nil 199 } 200 201 // Unsigned integers 202 if strings.HasPrefix(theType.String(), "[]uint") || theType.String() == "[]byte" { 203 204 // Decode the base64 string if the value type is []uint8 or it's alias []byte 205 // See: https://golang.org/pkg/encoding/json/#Marshal 206 // > Array and slice values encode as JSON arrays, except that []byte encodes as a base64-encoded string 207 if reflect.TypeOf(value).String() == "string" { 208 output, err := base64.StdEncoding.DecodeString(value.(string)) 209 if err != nil { 210 return reflect.Value{}, err 211 } 212 value = output 213 } 214 215 uints := reflect.ValueOf(value) 216 217 theValue = reflect.MakeSlice(theType, uints.Len(), uints.Len()) 218 for i := 0; i < uints.Len(); i++ { 219 uintValue, err := getUintValue(strings.Split(theType.String(), "[]")[1], uints.Index(i).Interface()) 220 if err != nil { 221 return reflect.Value{}, err 222 } 223 224 theValue.Index(i).SetUint(uintValue) 225 } 226 227 return theValue, nil 228 } 229 230 // Floating point numbers 231 if strings.HasPrefix(theType.String(), "[]float") { 232 floats := reflect.ValueOf(value) 233 234 theValue = reflect.MakeSlice(theType, floats.Len(), floats.Len()) 235 for i := 0; i < floats.Len(); i++ { 236 floatValue, err := getFloatValue(strings.Split(theType.String(), "[]")[1], floats.Index(i).Interface()) 237 if err != nil { 238 return reflect.Value{}, err 239 } 240 241 theValue.Index(i).SetFloat(floatValue) 242 } 243 244 return theValue, nil 245 } 246 247 // Strings 248 if theType.String() == "[]string" { 249 strs := reflect.ValueOf(value) 250 251 theValue = reflect.MakeSlice(theType, strs.Len(), strs.Len()) 252 for i := 0; i < strs.Len(); i++ { 253 strValue, err := getStringValue(strings.Split(theType.String(), "[]")[1], strs.Index(i).Interface()) 254 if err != nil { 255 return reflect.Value{}, err 256 } 257 258 theValue.Index(i).SetString(strValue) 259 } 260 261 return theValue, nil 262 } 263 264 return reflect.Value{}, NewErrNonsupportType(valueType) 265 } 266 267 func getBoolValue(theType string, value interface{}) (bool, error) { 268 b, ok := value.(bool) 269 if !ok { 270 return false, typeConversionError(value, typeOfMap[theType].String()) 271 } 272 273 return b, nil 274 } 275 276 func getIntValue(theType string, value interface{}) (int64, error) { 277 // We use https://golang.org/pkg/encoding/json/#Decoder.UseNumber when unmarshaling signatures. 278 // This is because JSON only supports 64-bit floating point numbers and we could lose precision 279 // when converting from float64 to signed integer 280 if strings.HasPrefix(fmt.Sprintf("%T", value), "json.Number") { 281 n, ok := value.(json.Number) 282 if !ok { 283 return 0, typeConversionError(value, typeOfMap[theType].String()) 284 } 285 286 return n.Int64() 287 } 288 289 n, ok := value.(int64) 290 if !ok { 291 return 0, typeConversionError(value, typeOfMap[theType].String()) 292 } 293 294 return n, nil 295 } 296 297 func getUintValue(theType string, value interface{}) (uint64, error) { 298 // We use https://golang.org/pkg/encoding/json/#Decoder.UseNumber when unmarshaling signatures. 299 // This is because JSON only supports 64-bit floating point numbers and we could lose precision 300 // when converting from float64 to unsigned integer 301 if strings.HasPrefix(fmt.Sprintf("%T", value), "json.Number") { 302 n, ok := value.(json.Number) 303 if !ok { 304 return 0, typeConversionError(value, typeOfMap[theType].String()) 305 } 306 307 intVal, err := n.Int64() 308 if err != nil { 309 return 0, err 310 } 311 312 return uint64(intVal), nil 313 } 314 315 var n uint64 316 switch value := value.(type) { 317 case uint64: 318 n = value 319 case uint8: 320 n = uint64(value) 321 default: 322 return 0, typeConversionError(value, typeOfMap[theType].String()) 323 } 324 return n, nil 325 } 326 327 func getFloatValue(theType string, value interface{}) (float64, error) { 328 // We use https://golang.org/pkg/encoding/json/#Decoder.UseNumber when unmarshaling signatures. 329 // This is because JSON only supports 64-bit floating point numbers and we could lose precision 330 if strings.HasPrefix(fmt.Sprintf("%T", value), "json.Number") { 331 n, ok := value.(json.Number) 332 if !ok { 333 return 0, typeConversionError(value, typeOfMap[theType].String()) 334 } 335 336 return n.Float64() 337 } 338 339 f, ok := value.(float64) 340 if !ok { 341 return 0, typeConversionError(value, typeOfMap[theType].String()) 342 } 343 344 return f, nil 345 } 346 347 func getStringValue(theType string, value interface{}) (string, error) { 348 s, ok := value.(string) 349 if !ok { 350 return "", typeConversionError(value, typeOfMap[theType].String()) 351 } 352 353 return s, nil 354 }