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  }