github.com/aws-cloudformation/cloudformation-cli-go-plugin@v1.2.0/cfn/encoding/stringify.go (about) 1 package encoding 2 3 import ( 4 "fmt" 5 "reflect" 6 "strings" 7 ) 8 9 func stringifyType(t reflect.Type) reflect.Type { 10 switch t.Kind() { 11 case reflect.Map: 12 return reflect.MapOf(stringType, interfaceType) 13 case reflect.Slice: 14 return reflect.SliceOf(interfaceType) 15 case reflect.Struct: 16 return stringifyStructType(t) 17 case reflect.Ptr: 18 return stringifyType(t.Elem()) 19 default: 20 return stringType 21 } 22 } 23 24 func stringifyStructType(t reflect.Type) reflect.Type { 25 fields := make([]reflect.StructField, t.NumField()) 26 27 for i := 0; i < t.NumField(); i++ { 28 f := t.Field(i) 29 30 fields[i] = reflect.StructField{ 31 Name: f.Name, 32 Type: stringifyType(f.Type), 33 Tag: f.Tag, 34 } 35 } 36 37 return reflect.StructOf(fields) 38 } 39 40 // Stringify converts any supported type into a stringified value 41 func Stringify(v interface{}) (interface{}, error) { 42 var err error 43 44 if v == nil { 45 return nil, nil 46 } 47 48 val := reflect.ValueOf(v) 49 50 switch val.Kind() { 51 case reflect.String, reflect.Bool, reflect.Int, reflect.Float64: 52 return fmt.Sprint(v), nil 53 case reflect.Map: 54 out := make(map[string]interface{}) 55 for _, key := range val.MapKeys() { 56 v, err := Stringify(val.MapIndex(key).Interface()) 57 switch { 58 case err != nil: 59 return nil, err 60 case v != nil: 61 out[key.String()] = v 62 } 63 } 64 return out, nil 65 case reflect.Slice: 66 out := make([]interface{}, val.Len()) 67 for i := 0; i < val.Len(); i++ { 68 v, err = Stringify(val.Index(i).Interface()) 69 switch { 70 case err != nil: 71 return nil, err 72 case v != nil: 73 out[i] = v 74 } 75 } 76 return out, nil 77 case reflect.Struct: 78 t := val.Type() 79 80 out := reflect.New(stringifyStructType(t)).Elem() 81 for i := 0; i < t.NumField(); i++ { 82 f := t.Field(i) 83 84 v := val.FieldByName(f.Name) 85 86 if tag, ok := f.Tag.Lookup("json"); ok { 87 if strings.Contains(tag, ",omitempty") { 88 if v.IsZero() { 89 continue 90 } 91 } 92 } 93 94 s, err := Stringify(v.Interface()) 95 switch { 96 case err != nil: 97 return nil, err 98 case s != nil: 99 out.Field(i).Set(reflect.ValueOf(s)) 100 } 101 } 102 103 return out.Interface(), nil 104 case reflect.Ptr: 105 if val.IsNil() { 106 return nil, nil 107 } 108 109 return Stringify(val.Elem().Interface()) 110 } 111 112 return nil, fmt.Errorf("Unsupported type: '%v'", val.Kind()) 113 }