github.com/aws-cloudformation/cloudformation-cli-go-plugin@v1.2.0/cfn/encoding/unstringify.go (about)

     1  package encoding
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"strconv"
     7  	"strings"
     8  )
     9  
    10  func convertStruct(i interface{}, t reflect.Type, pointer bool) (reflect.Value, error) {
    11  	m, ok := i.(map[string]interface{})
    12  	if !ok {
    13  		return zeroValue, fmt.Errorf("Cannot convert %T to struct", i)
    14  	}
    15  
    16  	out := reflect.New(t)
    17  
    18  	err := Unstringify(m, out.Interface())
    19  	if err != nil {
    20  		return zeroValue, err
    21  	}
    22  
    23  	if !pointer {
    24  		out = out.Elem()
    25  	}
    26  
    27  	return out, nil
    28  }
    29  
    30  func convertSlice(i interface{}, t reflect.Type, pointer bool) (reflect.Value, error) {
    31  	s, ok := i.([]interface{})
    32  	if !ok {
    33  		return zeroValue, fmt.Errorf("Cannot convert %T to slice", i)
    34  	}
    35  
    36  	out := reflect.New(t)
    37  	out.Elem().Set(reflect.MakeSlice(t, len(s), len(s)))
    38  
    39  	for j, v := range s {
    40  		val, err := convertType(t.Elem(), v)
    41  		if err != nil {
    42  			return zeroValue, err
    43  		}
    44  
    45  		out.Elem().Index(j).Set(val)
    46  	}
    47  
    48  	if !pointer {
    49  		out = out.Elem()
    50  	}
    51  
    52  	return out, nil
    53  }
    54  
    55  func convertMap(i interface{}, t reflect.Type, pointer bool) (reflect.Value, error) {
    56  	m, ok := i.(map[string]interface{})
    57  	if !ok {
    58  		return zeroValue, fmt.Errorf("Cannot convert %T to map with string keys", i)
    59  	}
    60  
    61  	out := reflect.New(t)
    62  	out.Elem().Set(reflect.MakeMap(t))
    63  
    64  	for k, v := range m {
    65  		val, err := convertType(t.Elem(), v)
    66  		if err != nil {
    67  			return zeroValue, err
    68  		}
    69  
    70  		out.Elem().SetMapIndex(reflect.ValueOf(k), val)
    71  	}
    72  
    73  	if !pointer {
    74  		out = out.Elem()
    75  	}
    76  
    77  	return out, nil
    78  }
    79  
    80  func convertString(i interface{}, pointer bool) (reflect.Value, error) {
    81  	s, ok := i.(string)
    82  
    83  	if !ok {
    84  		return zeroValue, fmt.Errorf("Cannot convert %T to string", i)
    85  	}
    86  
    87  	if pointer {
    88  		return reflect.ValueOf(&s), nil
    89  	}
    90  
    91  	return reflect.ValueOf(s), nil
    92  }
    93  
    94  func convertBool(i interface{}, pointer bool) (reflect.Value, error) {
    95  	var b bool
    96  	var err error
    97  
    98  	switch v := i.(type) {
    99  	case bool:
   100  		b = v
   101  
   102  	case string:
   103  		b, err = strconv.ParseBool(v)
   104  		if err != nil {
   105  			return zeroValue, err
   106  		}
   107  
   108  	default:
   109  		return zeroValue, fmt.Errorf("Cannot convert %T to bool", i)
   110  	}
   111  
   112  	if pointer {
   113  		return reflect.ValueOf(&b), nil
   114  	}
   115  
   116  	return reflect.ValueOf(b), nil
   117  }
   118  
   119  func convertInt(i interface{}, pointer bool) (reflect.Value, error) {
   120  	var n int
   121  
   122  	switch v := i.(type) {
   123  	case int:
   124  		n = v
   125  
   126  	case float64:
   127  		n = int(v)
   128  
   129  	case string:
   130  		n64, err := strconv.ParseInt(v, 0, 32)
   131  		if err != nil {
   132  			return zeroValue, err
   133  		}
   134  
   135  		n = int(n64)
   136  
   137  	default:
   138  		return zeroValue, fmt.Errorf("Cannot convert %T to bool", i)
   139  	}
   140  
   141  	if pointer {
   142  		return reflect.ValueOf(&n), nil
   143  	}
   144  
   145  	return reflect.ValueOf(n), nil
   146  }
   147  
   148  func convertFloat64(i interface{}, pointer bool) (reflect.Value, error) {
   149  	var f float64
   150  	var err error
   151  
   152  	switch v := i.(type) {
   153  	case float64:
   154  		f = v
   155  
   156  	case int:
   157  		f = float64(v)
   158  
   159  	case string:
   160  		f, err = strconv.ParseFloat(v, 64)
   161  		if err != nil {
   162  			return zeroValue, err
   163  		}
   164  
   165  	default:
   166  		return zeroValue, fmt.Errorf("Cannot convert %T to bool", i)
   167  	}
   168  
   169  	if pointer {
   170  		return reflect.ValueOf(&f), nil
   171  	}
   172  
   173  	return reflect.ValueOf(f), nil
   174  }
   175  
   176  func convertType(t reflect.Type, i interface{}) (reflect.Value, error) {
   177  	pointer := false
   178  	if t.Kind() == reflect.Ptr {
   179  		pointer = true
   180  		t = t.Elem()
   181  	}
   182  
   183  	switch t.Kind() {
   184  	case reflect.Struct:
   185  		return convertStruct(i, t, pointer)
   186  
   187  	case reflect.Slice:
   188  		return convertSlice(i, t, pointer)
   189  
   190  	case reflect.Map:
   191  		return convertMap(i, t, pointer)
   192  
   193  	case reflect.String:
   194  		return convertString(i, pointer)
   195  
   196  	case reflect.Bool:
   197  		return convertBool(i, pointer)
   198  
   199  	case reflect.Int:
   200  		return convertInt(i, pointer)
   201  
   202  	case reflect.Float64:
   203  		return convertFloat64(i, pointer)
   204  
   205  	default:
   206  		return zeroValue, fmt.Errorf("Unsupported type %v", t)
   207  	}
   208  }
   209  
   210  // Unstringify takes a stringified representation of a value
   211  // and populates it into the supplied interface
   212  func Unstringify(data map[string]interface{}, v interface{}) error {
   213  	t := reflect.TypeOf(v).Elem()
   214  
   215  	val := reflect.ValueOf(v).Elem()
   216  
   217  	for i := 0; i < t.NumField(); i++ {
   218  		f := t.Field(i)
   219  
   220  		jsonName := f.Name
   221  		jsonTag := strings.Split(f.Tag.Get("json"), ",")
   222  		if len(jsonTag) > 0 && jsonTag[0] != "" {
   223  			jsonName = jsonTag[0]
   224  		}
   225  
   226  		if value, ok := data[jsonName]; ok {
   227  			newValue, err := convertType(f.Type, value)
   228  			if err != nil {
   229  				return err
   230  			}
   231  
   232  			val.FieldByName(f.Name).Set(newValue)
   233  		}
   234  	}
   235  
   236  	return nil
   237  }