1// +build codegen
2
3package api
4
5import (
6	"encoding/json"
7	"fmt"
8	"reflect"
9	"strings"
10
11	"github.com/aws/aws-sdk-go/private/util"
12)
13
14// A paramFiller provides string formatting for a shape and its types.
15type paramFiller struct {
16	prefixPackageName bool
17}
18
19// typeName returns the type name of a shape.
20func (f paramFiller) typeName(shape *Shape) string {
21	if f.prefixPackageName && shape.Type == "structure" {
22		return "*" + shape.API.PackageName() + "." + shape.GoTypeElem()
23	}
24	return shape.GoType()
25}
26
27// ParamsStructFromJSON returns a JSON string representation of a structure.
28func ParamsStructFromJSON(value interface{}, shape *Shape, prefixPackageName bool) string {
29	f := paramFiller{prefixPackageName: prefixPackageName}
30	return util.GoFmt(f.paramsStructAny(value, shape))
31}
32
33// paramsStructAny returns the string representation of any value.
34func (f paramFiller) paramsStructAny(value interface{}, shape *Shape) string {
35	if value == nil {
36		return ""
37	}
38
39	switch shape.Type {
40	case "structure":
41		if value != nil {
42			vmap := value.(map[string]interface{})
43			return f.paramsStructStruct(vmap, shape)
44		}
45	case "list":
46		vlist := value.([]interface{})
47		return f.paramsStructList(vlist, shape)
48	case "map":
49		vmap := value.(map[string]interface{})
50		return f.paramsStructMap(vmap, shape)
51	case "string", "character":
52		v := reflect.Indirect(reflect.ValueOf(value))
53		if v.IsValid() {
54			return fmt.Sprintf("aws.String(%#v)", v.Interface())
55		}
56	case "blob":
57		v := reflect.Indirect(reflect.ValueOf(value))
58		if v.IsValid() && shape.Streaming {
59			return fmt.Sprintf("bytes.NewReader([]byte(%#v))", v.Interface())
60		} else if v.IsValid() {
61			return fmt.Sprintf("[]byte(%#v)", v.Interface())
62		}
63	case "boolean":
64		v := reflect.Indirect(reflect.ValueOf(value))
65		if v.IsValid() {
66			return fmt.Sprintf("aws.Bool(%#v)", v.Interface())
67		}
68	case "integer", "long":
69		v := reflect.Indirect(reflect.ValueOf(value))
70		if v.IsValid() {
71			return fmt.Sprintf("aws.Int64(%v)", v.Interface())
72		}
73	case "float", "double":
74		v := reflect.Indirect(reflect.ValueOf(value))
75		if v.IsValid() {
76			return fmt.Sprintf("aws.Float64(%v)", v.Interface())
77		}
78	case "timestamp":
79		v := reflect.Indirect(reflect.ValueOf(value))
80		if v.IsValid() {
81			return fmt.Sprintf("aws.Time(time.Unix(%d, 0))", int(v.Float()))
82		}
83	case "jsonvalue":
84		v, err := json.Marshal(value)
85		if err != nil {
86			panic("failed to marshal JSONValue, " + err.Error())
87		}
88		const tmpl = `func() aws.JSONValue {
89			var m aws.JSONValue
90			if err := json.Unmarshal([]byte(%q), &m); err != nil {
91				panic("failed to unmarshal JSONValue, "+err.Error())
92			}
93			return m
94		}()`
95		return fmt.Sprintf(tmpl, string(v))
96	default:
97		panic("Unhandled type " + shape.Type)
98	}
99	return ""
100}
101
102// paramsStructStruct returns the string representation of a structure
103func (f paramFiller) paramsStructStruct(value map[string]interface{}, shape *Shape) string {
104	out := "&" + f.typeName(shape)[1:] + "{\n"
105	for _, n := range shape.MemberNames() {
106		ref := shape.MemberRefs[n]
107		name := findParamMember(value, n)
108
109		if val := f.paramsStructAny(value[name], ref.Shape); val != "" {
110			out += fmt.Sprintf("%s: %s,\n", n, val)
111		}
112	}
113	out += "}"
114	return out
115}
116
117// paramsStructMap returns the string representation of a map of values
118func (f paramFiller) paramsStructMap(value map[string]interface{}, shape *Shape) string {
119	out := f.typeName(shape) + "{\n"
120	keys := util.SortedKeys(value)
121	for _, k := range keys {
122		v := value[k]
123		out += fmt.Sprintf("%q: %s,\n", k, f.paramsStructAny(v, shape.ValueRef.Shape))
124	}
125	out += "}"
126	return out
127}
128
129// paramsStructList returns the string representation of slice of values
130func (f paramFiller) paramsStructList(value []interface{}, shape *Shape) string {
131	out := f.typeName(shape) + "{\n"
132	for _, v := range value {
133		out += fmt.Sprintf("%s,\n", f.paramsStructAny(v, shape.MemberRef.Shape))
134	}
135	out += "}"
136	return out
137}
138
139// findParamMember searches a map for a key ignoring case. Returns the map key if found.
140func findParamMember(value map[string]interface{}, key string) string {
141	for actualKey := range value {
142		if strings.EqualFold(key, actualKey) {
143			return actualKey
144		}
145	}
146	return ""
147}
148