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