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  }