]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/aws/aws-sdk-go/private/protocol/query/queryutil/queryutil.go
Initial transfer of provider code
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / aws / aws-sdk-go / private / protocol / query / queryutil / queryutil.go
1 package queryutil
2
3 import (
4 "encoding/base64"
5 "fmt"
6 "net/url"
7 "reflect"
8 "sort"
9 "strconv"
10 "strings"
11 "time"
12
13 "github.com/aws/aws-sdk-go/private/protocol"
14 )
15
16 // Parse parses an object i and fills a url.Values object. The isEC2 flag
17 // indicates if this is the EC2 Query sub-protocol.
18 func Parse(body url.Values, i interface{}, isEC2 bool) error {
19 q := queryParser{isEC2: isEC2}
20 return q.parseValue(body, reflect.ValueOf(i), "", "")
21 }
22
23 func elemOf(value reflect.Value) reflect.Value {
24 for value.Kind() == reflect.Ptr {
25 value = value.Elem()
26 }
27 return value
28 }
29
30 type queryParser struct {
31 isEC2 bool
32 }
33
34 func (q *queryParser) parseValue(v url.Values, value reflect.Value, prefix string, tag reflect.StructTag) error {
35 value = elemOf(value)
36
37 // no need to handle zero values
38 if !value.IsValid() {
39 return nil
40 }
41
42 t := tag.Get("type")
43 if t == "" {
44 switch value.Kind() {
45 case reflect.Struct:
46 t = "structure"
47 case reflect.Slice:
48 t = "list"
49 case reflect.Map:
50 t = "map"
51 }
52 }
53
54 switch t {
55 case "structure":
56 return q.parseStruct(v, value, prefix)
57 case "list":
58 return q.parseList(v, value, prefix, tag)
59 case "map":
60 return q.parseMap(v, value, prefix, tag)
61 default:
62 return q.parseScalar(v, value, prefix, tag)
63 }
64 }
65
66 func (q *queryParser) parseStruct(v url.Values, value reflect.Value, prefix string) error {
67 if !value.IsValid() {
68 return nil
69 }
70
71 t := value.Type()
72 for i := 0; i < value.NumField(); i++ {
73 elemValue := elemOf(value.Field(i))
74 field := t.Field(i)
75
76 if field.PkgPath != "" {
77 continue // ignore unexported fields
78 }
79 if field.Tag.Get("ignore") != "" {
80 continue
81 }
82
83 if protocol.CanSetIdempotencyToken(value.Field(i), field) {
84 token := protocol.GetIdempotencyToken()
85 elemValue = reflect.ValueOf(token)
86 }
87
88 var name string
89 if q.isEC2 {
90 name = field.Tag.Get("queryName")
91 }
92 if name == "" {
93 if field.Tag.Get("flattened") != "" && field.Tag.Get("locationNameList") != "" {
94 name = field.Tag.Get("locationNameList")
95 } else if locName := field.Tag.Get("locationName"); locName != "" {
96 name = locName
97 }
98 if name != "" && q.isEC2 {
99 name = strings.ToUpper(name[0:1]) + name[1:]
100 }
101 }
102 if name == "" {
103 name = field.Name
104 }
105
106 if prefix != "" {
107 name = prefix + "." + name
108 }
109
110 if err := q.parseValue(v, elemValue, name, field.Tag); err != nil {
111 return err
112 }
113 }
114 return nil
115 }
116
117 func (q *queryParser) parseList(v url.Values, value reflect.Value, prefix string, tag reflect.StructTag) error {
118 // If it's empty, generate an empty value
119 if !value.IsNil() && value.Len() == 0 {
120 v.Set(prefix, "")
121 return nil
122 }
123
124 // check for unflattened list member
125 if !q.isEC2 && tag.Get("flattened") == "" {
126 if listName := tag.Get("locationNameList"); listName == "" {
127 prefix += ".member"
128 } else {
129 prefix += "." + listName
130 }
131 }
132
133 for i := 0; i < value.Len(); i++ {
134 slicePrefix := prefix
135 if slicePrefix == "" {
136 slicePrefix = strconv.Itoa(i + 1)
137 } else {
138 slicePrefix = slicePrefix + "." + strconv.Itoa(i+1)
139 }
140 if err := q.parseValue(v, value.Index(i), slicePrefix, ""); err != nil {
141 return err
142 }
143 }
144 return nil
145 }
146
147 func (q *queryParser) parseMap(v url.Values, value reflect.Value, prefix string, tag reflect.StructTag) error {
148 // If it's empty, generate an empty value
149 if !value.IsNil() && value.Len() == 0 {
150 v.Set(prefix, "")
151 return nil
152 }
153
154 // check for unflattened list member
155 if !q.isEC2 && tag.Get("flattened") == "" {
156 prefix += ".entry"
157 }
158
159 // sort keys for improved serialization consistency.
160 // this is not strictly necessary for protocol support.
161 mapKeyValues := value.MapKeys()
162 mapKeys := map[string]reflect.Value{}
163 mapKeyNames := make([]string, len(mapKeyValues))
164 for i, mapKey := range mapKeyValues {
165 name := mapKey.String()
166 mapKeys[name] = mapKey
167 mapKeyNames[i] = name
168 }
169 sort.Strings(mapKeyNames)
170
171 for i, mapKeyName := range mapKeyNames {
172 mapKey := mapKeys[mapKeyName]
173 mapValue := value.MapIndex(mapKey)
174
175 kname := tag.Get("locationNameKey")
176 if kname == "" {
177 kname = "key"
178 }
179 vname := tag.Get("locationNameValue")
180 if vname == "" {
181 vname = "value"
182 }
183
184 // serialize key
185 var keyName string
186 if prefix == "" {
187 keyName = strconv.Itoa(i+1) + "." + kname
188 } else {
189 keyName = prefix + "." + strconv.Itoa(i+1) + "." + kname
190 }
191
192 if err := q.parseValue(v, mapKey, keyName, ""); err != nil {
193 return err
194 }
195
196 // serialize value
197 var valueName string
198 if prefix == "" {
199 valueName = strconv.Itoa(i+1) + "." + vname
200 } else {
201 valueName = prefix + "." + strconv.Itoa(i+1) + "." + vname
202 }
203
204 if err := q.parseValue(v, mapValue, valueName, ""); err != nil {
205 return err
206 }
207 }
208
209 return nil
210 }
211
212 func (q *queryParser) parseScalar(v url.Values, r reflect.Value, name string, tag reflect.StructTag) error {
213 switch value := r.Interface().(type) {
214 case string:
215 v.Set(name, value)
216 case []byte:
217 if !r.IsNil() {
218 v.Set(name, base64.StdEncoding.EncodeToString(value))
219 }
220 case bool:
221 v.Set(name, strconv.FormatBool(value))
222 case int64:
223 v.Set(name, strconv.FormatInt(value, 10))
224 case int:
225 v.Set(name, strconv.Itoa(value))
226 case float64:
227 v.Set(name, strconv.FormatFloat(value, 'f', -1, 64))
228 case float32:
229 v.Set(name, strconv.FormatFloat(float64(value), 'f', -1, 32))
230 case time.Time:
231 const ISO8601UTC = "2006-01-02T15:04:05Z"
232 v.Set(name, value.UTC().Format(ISO8601UTC))
233 default:
234 return fmt.Errorf("unsupported value for param %s: %v (%s)", name, r.Interface(), r.Type().Name())
235 }
236 return nil
237 }