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  }