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 }