aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/mitchellh/mapstructure
diff options
context:
space:
mode:
authorJake Champlin <jake.champlin.27@gmail.com>2017-06-06 12:40:07 -0400
committerJake Champlin <jake.champlin.27@gmail.com>2017-06-06 12:40:07 -0400
commitbae9f6d2fd5eb5bc80929bd393932b23f14d7c93 (patch)
treeca9ab12a7d78b1fc27a8f734729081357ce6d252 /vendor/github.com/mitchellh/mapstructure
parent254c495b6bebab3fb72a243c4bce858d79e6ee99 (diff)
downloadterraform-provider-statuscake-bae9f6d2fd5eb5bc80929bd393932b23f14d7c93.tar.gz
terraform-provider-statuscake-bae9f6d2fd5eb5bc80929bd393932b23f14d7c93.tar.zst
terraform-provider-statuscake-bae9f6d2fd5eb5bc80929bd393932b23f14d7c93.zip
Initial transfer of provider code
Diffstat (limited to 'vendor/github.com/mitchellh/mapstructure')
-rw-r--r--vendor/github.com/mitchellh/mapstructure/LICENSE21
-rw-r--r--vendor/github.com/mitchellh/mapstructure/README.md46
-rw-r--r--vendor/github.com/mitchellh/mapstructure/decode_hooks.go154
-rw-r--r--vendor/github.com/mitchellh/mapstructure/error.go50
-rw-r--r--vendor/github.com/mitchellh/mapstructure/mapstructure.go823
5 files changed, 1094 insertions, 0 deletions
diff --git a/vendor/github.com/mitchellh/mapstructure/LICENSE b/vendor/github.com/mitchellh/mapstructure/LICENSE
new file mode 100644
index 0000000..f9c841a
--- /dev/null
+++ b/vendor/github.com/mitchellh/mapstructure/LICENSE
@@ -0,0 +1,21 @@
1The MIT License (MIT)
2
3Copyright (c) 2013 Mitchell Hashimoto
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21THE SOFTWARE.
diff --git a/vendor/github.com/mitchellh/mapstructure/README.md b/vendor/github.com/mitchellh/mapstructure/README.md
new file mode 100644
index 0000000..659d688
--- /dev/null
+++ b/vendor/github.com/mitchellh/mapstructure/README.md
@@ -0,0 +1,46 @@
1# mapstructure
2
3mapstructure is a Go library for decoding generic map values to structures
4and vice versa, while providing helpful error handling.
5
6This library is most useful when decoding values from some data stream (JSON,
7Gob, etc.) where you don't _quite_ know the structure of the underlying data
8until you read a part of it. You can therefore read a `map[string]interface{}`
9and use this library to decode it into the proper underlying native Go
10structure.
11
12## Installation
13
14Standard `go get`:
15
16```
17$ go get github.com/mitchellh/mapstructure
18```
19
20## Usage & Example
21
22For usage and examples see the [Godoc](http://godoc.org/github.com/mitchellh/mapstructure).
23
24The `Decode` function has examples associated with it there.
25
26## But Why?!
27
28Go offers fantastic standard libraries for decoding formats such as JSON.
29The standard method is to have a struct pre-created, and populate that struct
30from the bytes of the encoded format. This is great, but the problem is if
31you have configuration or an encoding that changes slightly depending on
32specific fields. For example, consider this JSON:
33
34```json
35{
36 "type": "person",
37 "name": "Mitchell"
38}
39```
40
41Perhaps we can't populate a specific structure without first reading
42the "type" field from the JSON. We could always do two passes over the
43decoding of the JSON (reading the "type" first, and the rest later).
44However, it is much simpler to just decode this into a `map[string]interface{}`
45structure, read the "type" key, then use something like this library
46to decode it into the proper structure.
diff --git a/vendor/github.com/mitchellh/mapstructure/decode_hooks.go b/vendor/github.com/mitchellh/mapstructure/decode_hooks.go
new file mode 100644
index 0000000..115ae67
--- /dev/null
+++ b/vendor/github.com/mitchellh/mapstructure/decode_hooks.go
@@ -0,0 +1,154 @@
1package mapstructure
2
3import (
4 "errors"
5 "reflect"
6 "strconv"
7 "strings"
8 "time"
9)
10
11// typedDecodeHook takes a raw DecodeHookFunc (an interface{}) and turns
12// it into the proper DecodeHookFunc type, such as DecodeHookFuncType.
13func typedDecodeHook(h DecodeHookFunc) DecodeHookFunc {
14 // Create variables here so we can reference them with the reflect pkg
15 var f1 DecodeHookFuncType
16 var f2 DecodeHookFuncKind
17
18 // Fill in the variables into this interface and the rest is done
19 // automatically using the reflect package.
20 potential := []interface{}{f1, f2}
21
22 v := reflect.ValueOf(h)
23 vt := v.Type()
24 for _, raw := range potential {
25 pt := reflect.ValueOf(raw).Type()
26 if vt.ConvertibleTo(pt) {
27 return v.Convert(pt).Interface()
28 }
29 }
30
31 return nil
32}
33
34// DecodeHookExec executes the given decode hook. This should be used
35// since it'll naturally degrade to the older backwards compatible DecodeHookFunc
36// that took reflect.Kind instead of reflect.Type.
37func DecodeHookExec(
38 raw DecodeHookFunc,
39 from reflect.Type, to reflect.Type,
40 data interface{}) (interface{}, error) {
41 // Build our arguments that reflect expects
42 argVals := make([]reflect.Value, 3)
43 argVals[0] = reflect.ValueOf(from)
44 argVals[1] = reflect.ValueOf(to)
45 argVals[2] = reflect.ValueOf(data)
46
47 switch f := typedDecodeHook(raw).(type) {
48 case DecodeHookFuncType:
49 return f(from, to, data)
50 case DecodeHookFuncKind:
51 return f(from.Kind(), to.Kind(), data)
52 default:
53 return nil, errors.New("invalid decode hook signature")
54 }
55}
56
57// ComposeDecodeHookFunc creates a single DecodeHookFunc that
58// automatically composes multiple DecodeHookFuncs.
59//
60// The composed funcs are called in order, with the result of the
61// previous transformation.
62func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc {
63 return func(
64 f reflect.Type,
65 t reflect.Type,
66 data interface{}) (interface{}, error) {
67 var err error
68 for _, f1 := range fs {
69 data, err = DecodeHookExec(f1, f, t, data)
70 if err != nil {
71 return nil, err
72 }
73
74 // Modify the from kind to be correct with the new data
75 f = nil
76 if val := reflect.ValueOf(data); val.IsValid() {
77 f = val.Type()
78 }
79 }
80
81 return data, nil
82 }
83}
84
85// StringToSliceHookFunc returns a DecodeHookFunc that converts
86// string to []string by splitting on the given sep.
87func StringToSliceHookFunc(sep string) DecodeHookFunc {
88 return func(
89 f reflect.Kind,
90 t reflect.Kind,
91 data interface{}) (interface{}, error) {
92 if f != reflect.String || t != reflect.Slice {
93 return data, nil
94 }
95
96 raw := data.(string)
97 if raw == "" {
98 return []string{}, nil
99 }
100
101 return strings.Split(raw, sep), nil
102 }
103}
104
105// StringToTimeDurationHookFunc returns a DecodeHookFunc that converts
106// strings to time.Duration.
107func StringToTimeDurationHookFunc() DecodeHookFunc {
108 return func(
109 f reflect.Type,
110 t reflect.Type,
111 data interface{}) (interface{}, error) {
112 if f.Kind() != reflect.String {
113 return data, nil
114 }
115 if t != reflect.TypeOf(time.Duration(5)) {
116 return data, nil
117 }
118
119 // Convert it by parsing
120 return time.ParseDuration(data.(string))
121 }
122}
123
124func WeaklyTypedHook(
125 f reflect.Kind,
126 t reflect.Kind,
127 data interface{}) (interface{}, error) {
128 dataVal := reflect.ValueOf(data)
129 switch t {
130 case reflect.String:
131 switch f {
132 case reflect.Bool:
133 if dataVal.Bool() {
134 return "1", nil
135 } else {
136 return "0", nil
137 }
138 case reflect.Float32:
139 return strconv.FormatFloat(dataVal.Float(), 'f', -1, 64), nil
140 case reflect.Int:
141 return strconv.FormatInt(dataVal.Int(), 10), nil
142 case reflect.Slice:
143 dataType := dataVal.Type()
144 elemKind := dataType.Elem().Kind()
145 if elemKind == reflect.Uint8 {
146 return string(dataVal.Interface().([]uint8)), nil
147 }
148 case reflect.Uint:
149 return strconv.FormatUint(dataVal.Uint(), 10), nil
150 }
151 }
152
153 return data, nil
154}
diff --git a/vendor/github.com/mitchellh/mapstructure/error.go b/vendor/github.com/mitchellh/mapstructure/error.go
new file mode 100644
index 0000000..47a99e5
--- /dev/null
+++ b/vendor/github.com/mitchellh/mapstructure/error.go
@@ -0,0 +1,50 @@
1package mapstructure
2
3import (
4 "errors"
5 "fmt"
6 "sort"
7 "strings"
8)
9
10// Error implements the error interface and can represents multiple
11// errors that occur in the course of a single decode.
12type Error struct {
13 Errors []string
14}
15
16func (e *Error) Error() string {
17 points := make([]string, len(e.Errors))
18 for i, err := range e.Errors {
19 points[i] = fmt.Sprintf("* %s", err)
20 }
21
22 sort.Strings(points)
23 return fmt.Sprintf(
24 "%d error(s) decoding:\n\n%s",
25 len(e.Errors), strings.Join(points, "\n"))
26}
27
28// WrappedErrors implements the errwrap.Wrapper interface to make this
29// return value more useful with the errwrap and go-multierror libraries.
30func (e *Error) WrappedErrors() []error {
31 if e == nil {
32 return nil
33 }
34
35 result := make([]error, len(e.Errors))
36 for i, e := range e.Errors {
37 result[i] = errors.New(e)
38 }
39
40 return result
41}
42
43func appendErrors(errors []string, err error) []string {
44 switch e := err.(type) {
45 case *Error:
46 return append(errors, e.Errors...)
47 default:
48 return append(errors, e.Error())
49 }
50}
diff --git a/vendor/github.com/mitchellh/mapstructure/mapstructure.go b/vendor/github.com/mitchellh/mapstructure/mapstructure.go
new file mode 100644
index 0000000..6dee0ef
--- /dev/null
+++ b/vendor/github.com/mitchellh/mapstructure/mapstructure.go
@@ -0,0 +1,823 @@
1// The mapstructure package exposes functionality to convert an
2// arbitrary map[string]interface{} into a native Go structure.
3//
4// The Go structure can be arbitrarily complex, containing slices,
5// other structs, etc. and the decoder will properly decode nested
6// maps and so on into the proper structures in the native Go struct.
7// See the examples to see what the decoder is capable of.
8package mapstructure
9
10import (
11 "encoding/json"
12 "errors"
13 "fmt"
14 "reflect"
15 "sort"
16 "strconv"
17 "strings"
18)
19
20// DecodeHookFunc is the callback function that can be used for
21// data transformations. See "DecodeHook" in the DecoderConfig
22// struct.
23//
24// The type should be DecodeHookFuncType or DecodeHookFuncKind.
25// Either is accepted. Types are a superset of Kinds (Types can return
26// Kinds) and are generally a richer thing to use, but Kinds are simpler
27// if you only need those.
28//
29// The reason DecodeHookFunc is multi-typed is for backwards compatibility:
30// we started with Kinds and then realized Types were the better solution,
31// but have a promise to not break backwards compat so we now support
32// both.
33type DecodeHookFunc interface{}
34
35type DecodeHookFuncType func(reflect.Type, reflect.Type, interface{}) (interface{}, error)
36type DecodeHookFuncKind func(reflect.Kind, reflect.Kind, interface{}) (interface{}, error)
37
38// DecoderConfig is the configuration that is used to create a new decoder
39// and allows customization of various aspects of decoding.
40type DecoderConfig struct {
41 // DecodeHook, if set, will be called before any decoding and any
42 // type conversion (if WeaklyTypedInput is on). This lets you modify
43 // the values before they're set down onto the resulting struct.
44 //
45 // If an error is returned, the entire decode will fail with that
46 // error.
47 DecodeHook DecodeHookFunc
48
49 // If ErrorUnused is true, then it is an error for there to exist
50 // keys in the original map that were unused in the decoding process
51 // (extra keys).
52 ErrorUnused bool
53
54 // ZeroFields, if set to true, will zero fields before writing them.
55 // For example, a map will be emptied before decoded values are put in
56 // it. If this is false, a map will be merged.
57 ZeroFields bool
58
59 // If WeaklyTypedInput is true, the decoder will make the following
60 // "weak" conversions:
61 //
62 // - bools to string (true = "1", false = "0")
63 // - numbers to string (base 10)
64 // - bools to int/uint (true = 1, false = 0)
65 // - strings to int/uint (base implied by prefix)
66 // - int to bool (true if value != 0)
67 // - string to bool (accepts: 1, t, T, TRUE, true, True, 0, f, F,
68 // FALSE, false, False. Anything else is an error)
69 // - empty array = empty map and vice versa
70 // - negative numbers to overflowed uint values (base 10)
71 // - slice of maps to a merged map
72 // - single values are converted to slices if required. Each
73 // element is weakly decoded. For example: "4" can become []int{4}
74 // if the target type is an int slice.
75 //
76 WeaklyTypedInput bool
77
78 // Metadata is the struct that will contain extra metadata about
79 // the decoding. If this is nil, then no metadata will be tracked.
80 Metadata *Metadata
81
82 // Result is a pointer to the struct that will contain the decoded
83 // value.
84 Result interface{}
85
86 // The tag name that mapstructure reads for field names. This
87 // defaults to "mapstructure"
88 TagName string
89}
90
91// A Decoder takes a raw interface value and turns it into structured
92// data, keeping track of rich error information along the way in case
93// anything goes wrong. Unlike the basic top-level Decode method, you can
94// more finely control how the Decoder behaves using the DecoderConfig
95// structure. The top-level Decode method is just a convenience that sets
96// up the most basic Decoder.
97type Decoder struct {
98 config *DecoderConfig
99}
100
101// Metadata contains information about decoding a structure that
102// is tedious or difficult to get otherwise.
103type Metadata struct {
104 // Keys are the keys of the structure which were successfully decoded
105 Keys []string
106
107 // Unused is a slice of keys that were found in the raw value but
108 // weren't decoded since there was no matching field in the result interface
109 Unused []string
110}
111
112// Decode takes a map and uses reflection to convert it into the
113// given Go native structure. val must be a pointer to a struct.
114func Decode(m interface{}, rawVal interface{}) error {
115 config := &DecoderConfig{
116 Metadata: nil,
117 Result: rawVal,
118 }
119
120 decoder, err := NewDecoder(config)
121 if err != nil {
122 return err
123 }
124
125 return decoder.Decode(m)
126}
127
128// WeakDecode is the same as Decode but is shorthand to enable
129// WeaklyTypedInput. See DecoderConfig for more info.
130func WeakDecode(input, output interface{}) error {
131 config := &DecoderConfig{
132 Metadata: nil,
133 Result: output,
134 WeaklyTypedInput: true,
135 }
136
137 decoder, err := NewDecoder(config)
138 if err != nil {
139 return err
140 }
141
142 return decoder.Decode(input)
143}
144
145// NewDecoder returns a new decoder for the given configuration. Once
146// a decoder has been returned, the same configuration must not be used
147// again.
148func NewDecoder(config *DecoderConfig) (*Decoder, error) {
149 val := reflect.ValueOf(config.Result)
150 if val.Kind() != reflect.Ptr {
151 return nil, errors.New("result must be a pointer")
152 }
153
154 val = val.Elem()
155 if !val.CanAddr() {
156 return nil, errors.New("result must be addressable (a pointer)")
157 }
158
159 if config.Metadata != nil {
160 if config.Metadata.Keys == nil {
161 config.Metadata.Keys = make([]string, 0)
162 }
163
164 if config.Metadata.Unused == nil {
165 config.Metadata.Unused = make([]string, 0)
166 }
167 }
168
169 if config.TagName == "" {
170 config.TagName = "mapstructure"
171 }
172
173 result := &Decoder{
174 config: config,
175 }
176
177 return result, nil
178}
179
180// Decode decodes the given raw interface to the target pointer specified
181// by the configuration.
182func (d *Decoder) Decode(raw interface{}) error {
183 return d.decode("", raw, reflect.ValueOf(d.config.Result).Elem())
184}
185
186// Decodes an unknown data type into a specific reflection value.
187func (d *Decoder) decode(name string, data interface{}, val reflect.Value) error {
188 if data == nil {
189 // If the data is nil, then we don't set anything.
190 return nil
191 }
192
193 dataVal := reflect.ValueOf(data)
194 if !dataVal.IsValid() {
195 // If the data value is invalid, then we just set the value
196 // to be the zero value.
197 val.Set(reflect.Zero(val.Type()))
198 return nil
199 }
200
201 if d.config.DecodeHook != nil {
202 // We have a DecodeHook, so let's pre-process the data.
203 var err error
204 data, err = DecodeHookExec(
205 d.config.DecodeHook,
206 dataVal.Type(), val.Type(), data)
207 if err != nil {
208 return fmt.Errorf("error decoding '%s': %s", name, err)
209 }
210 }
211
212 var err error
213 dataKind := getKind(val)
214 switch dataKind {
215 case reflect.Bool:
216 err = d.decodeBool(name, data, val)
217 case reflect.Interface:
218 err = d.decodeBasic(name, data, val)
219 case reflect.String:
220 err = d.decodeString(name, data, val)
221 case reflect.Int:
222 err = d.decodeInt(name, data, val)
223 case reflect.Uint:
224 err = d.decodeUint(name, data, val)
225 case reflect.Float32:
226 err = d.decodeFloat(name, data, val)
227 case reflect.Struct:
228 err = d.decodeStruct(name, data, val)
229 case reflect.Map:
230 err = d.decodeMap(name, data, val)
231 case reflect.Ptr:
232 err = d.decodePtr(name, data, val)
233 case reflect.Slice:
234 err = d.decodeSlice(name, data, val)
235 case reflect.Func:
236 err = d.decodeFunc(name, data, val)
237 default:
238 // If we reached this point then we weren't able to decode it
239 return fmt.Errorf("%s: unsupported type: %s", name, dataKind)
240 }
241
242 // If we reached here, then we successfully decoded SOMETHING, so
243 // mark the key as used if we're tracking metadata.
244 if d.config.Metadata != nil && name != "" {
245 d.config.Metadata.Keys = append(d.config.Metadata.Keys, name)
246 }
247
248 return err
249}
250
251// This decodes a basic type (bool, int, string, etc.) and sets the
252// value to "data" of that type.
253func (d *Decoder) decodeBasic(name string, data interface{}, val reflect.Value) error {
254 dataVal := reflect.ValueOf(data)
255 if !dataVal.IsValid() {
256 dataVal = reflect.Zero(val.Type())
257 }
258
259 dataValType := dataVal.Type()
260 if !dataValType.AssignableTo(val.Type()) {
261 return fmt.Errorf(
262 "'%s' expected type '%s', got '%s'",
263 name, val.Type(), dataValType)
264 }
265
266 val.Set(dataVal)
267 return nil
268}
269
270func (d *Decoder) decodeString(name string, data interface{}, val reflect.Value) error {
271 dataVal := reflect.ValueOf(data)
272 dataKind := getKind(dataVal)
273
274 converted := true
275 switch {
276 case dataKind == reflect.String:
277 val.SetString(dataVal.String())
278 case dataKind == reflect.Bool && d.config.WeaklyTypedInput:
279 if dataVal.Bool() {
280 val.SetString("1")
281 } else {
282 val.SetString("0")
283 }
284 case dataKind == reflect.Int && d.config.WeaklyTypedInput:
285 val.SetString(strconv.FormatInt(dataVal.Int(), 10))
286 case dataKind == reflect.Uint && d.config.WeaklyTypedInput:
287 val.SetString(strconv.FormatUint(dataVal.Uint(), 10))
288 case dataKind == reflect.Float32 && d.config.WeaklyTypedInput:
289 val.SetString(strconv.FormatFloat(dataVal.Float(), 'f', -1, 64))
290 case dataKind == reflect.Slice && d.config.WeaklyTypedInput:
291 dataType := dataVal.Type()
292 elemKind := dataType.Elem().Kind()
293 switch {
294 case elemKind == reflect.Uint8:
295 val.SetString(string(dataVal.Interface().([]uint8)))
296 default:
297 converted = false
298 }
299 default:
300 converted = false
301 }
302
303 if !converted {
304 return fmt.Errorf(
305 "'%s' expected type '%s', got unconvertible type '%s'",
306 name, val.Type(), dataVal.Type())
307 }
308
309 return nil
310}
311
312func (d *Decoder) decodeInt(name string, data interface{}, val reflect.Value) error {
313 dataVal := reflect.ValueOf(data)
314 dataKind := getKind(dataVal)
315 dataType := dataVal.Type()
316
317 switch {
318 case dataKind == reflect.Int:
319 val.SetInt(dataVal.Int())
320 case dataKind == reflect.Uint:
321 val.SetInt(int64(dataVal.Uint()))
322 case dataKind == reflect.Float32:
323 val.SetInt(int64(dataVal.Float()))
324 case dataKind == reflect.Bool && d.config.WeaklyTypedInput:
325 if dataVal.Bool() {
326 val.SetInt(1)
327 } else {
328 val.SetInt(0)
329 }
330 case dataKind == reflect.String && d.config.WeaklyTypedInput:
331 i, err := strconv.ParseInt(dataVal.String(), 0, val.Type().Bits())
332 if err == nil {
333 val.SetInt(i)
334 } else {
335 return fmt.Errorf("cannot parse '%s' as int: %s", name, err)
336 }
337 case dataType.PkgPath() == "encoding/json" && dataType.Name() == "Number":
338 jn := data.(json.Number)
339 i, err := jn.Int64()
340 if err != nil {
341 return fmt.Errorf(
342 "error decoding json.Number into %s: %s", name, err)
343 }
344 val.SetInt(i)
345 default:
346 return fmt.Errorf(
347 "'%s' expected type '%s', got unconvertible type '%s'",
348 name, val.Type(), dataVal.Type())
349 }
350
351 return nil
352}
353
354func (d *Decoder) decodeUint(name string, data interface{}, val reflect.Value) error {
355 dataVal := reflect.ValueOf(data)
356 dataKind := getKind(dataVal)
357
358 switch {
359 case dataKind == reflect.Int:
360 i := dataVal.Int()
361 if i < 0 && !d.config.WeaklyTypedInput {
362 return fmt.Errorf("cannot parse '%s', %d overflows uint",
363 name, i)
364 }
365 val.SetUint(uint64(i))
366 case dataKind == reflect.Uint:
367 val.SetUint(dataVal.Uint())
368 case dataKind == reflect.Float32:
369 f := dataVal.Float()
370 if f < 0 && !d.config.WeaklyTypedInput {
371 return fmt.Errorf("cannot parse '%s', %f overflows uint",
372 name, f)
373 }
374 val.SetUint(uint64(f))
375 case dataKind == reflect.Bool && d.config.WeaklyTypedInput:
376 if dataVal.Bool() {
377 val.SetUint(1)
378 } else {
379 val.SetUint(0)
380 }
381 case dataKind == reflect.String && d.config.WeaklyTypedInput:
382 i, err := strconv.ParseUint(dataVal.String(), 0, val.Type().Bits())
383 if err == nil {
384 val.SetUint(i)
385 } else {
386 return fmt.Errorf("cannot parse '%s' as uint: %s", name, err)
387 }
388 default:
389 return fmt.Errorf(
390 "'%s' expected type '%s', got unconvertible type '%s'",
391 name, val.Type(), dataVal.Type())
392 }
393
394 return nil
395}
396
397func (d *Decoder) decodeBool(name string, data interface{}, val reflect.Value) error {
398 dataVal := reflect.ValueOf(data)
399 dataKind := getKind(dataVal)
400
401 switch {
402 case dataKind == reflect.Bool:
403 val.SetBool(dataVal.Bool())
404 case dataKind == reflect.Int && d.config.WeaklyTypedInput:
405 val.SetBool(dataVal.Int() != 0)
406 case dataKind == reflect.Uint && d.config.WeaklyTypedInput:
407 val.SetBool(dataVal.Uint() != 0)
408 case dataKind == reflect.Float32 && d.config.WeaklyTypedInput:
409 val.SetBool(dataVal.Float() != 0)
410 case dataKind == reflect.String && d.config.WeaklyTypedInput:
411 b, err := strconv.ParseBool(dataVal.String())
412 if err == nil {
413 val.SetBool(b)
414 } else if dataVal.String() == "" {
415 val.SetBool(false)
416 } else {
417 return fmt.Errorf("cannot parse '%s' as bool: %s", name, err)
418 }
419 default:
420 return fmt.Errorf(
421 "'%s' expected type '%s', got unconvertible type '%s'",
422 name, val.Type(), dataVal.Type())
423 }
424
425 return nil
426}
427
428func (d *Decoder) decodeFloat(name string, data interface{}, val reflect.Value) error {
429 dataVal := reflect.ValueOf(data)
430 dataKind := getKind(dataVal)
431 dataType := dataVal.Type()
432
433 switch {
434 case dataKind == reflect.Int:
435 val.SetFloat(float64(dataVal.Int()))
436 case dataKind == reflect.Uint:
437 val.SetFloat(float64(dataVal.Uint()))
438 case dataKind == reflect.Float32:
439 val.SetFloat(float64(dataVal.Float()))
440 case dataKind == reflect.Bool && d.config.WeaklyTypedInput:
441 if dataVal.Bool() {
442 val.SetFloat(1)
443 } else {
444 val.SetFloat(0)
445 }
446 case dataKind == reflect.String && d.config.WeaklyTypedInput:
447 f, err := strconv.ParseFloat(dataVal.String(), val.Type().Bits())
448 if err == nil {
449 val.SetFloat(f)
450 } else {
451 return fmt.Errorf("cannot parse '%s' as float: %s", name, err)
452 }
453 case dataType.PkgPath() == "encoding/json" && dataType.Name() == "Number":
454 jn := data.(json.Number)
455 i, err := jn.Float64()
456 if err != nil {
457 return fmt.Errorf(
458 "error decoding json.Number into %s: %s", name, err)
459 }
460 val.SetFloat(i)
461 default:
462 return fmt.Errorf(
463 "'%s' expected type '%s', got unconvertible type '%s'",
464 name, val.Type(), dataVal.Type())
465 }
466
467 return nil
468}
469
470func (d *Decoder) decodeMap(name string, data interface{}, val reflect.Value) error {
471 valType := val.Type()
472 valKeyType := valType.Key()
473 valElemType := valType.Elem()
474
475 // By default we overwrite keys in the current map
476 valMap := val
477
478 // If the map is nil or we're purposely zeroing fields, make a new map
479 if valMap.IsNil() || d.config.ZeroFields {
480 // Make a new map to hold our result
481 mapType := reflect.MapOf(valKeyType, valElemType)
482 valMap = reflect.MakeMap(mapType)
483 }
484
485 // Check input type
486 dataVal := reflect.Indirect(reflect.ValueOf(data))
487 if dataVal.Kind() != reflect.Map {
488 // In weak mode, we accept a slice of maps as an input...
489 if d.config.WeaklyTypedInput {
490 switch dataVal.Kind() {
491 case reflect.Array, reflect.Slice:
492 // Special case for BC reasons (covered by tests)
493 if dataVal.Len() == 0 {
494 val.Set(valMap)
495 return nil
496 }
497
498 for i := 0; i < dataVal.Len(); i++ {
499 err := d.decode(
500 fmt.Sprintf("%s[%d]", name, i),
501 dataVal.Index(i).Interface(), val)
502 if err != nil {
503 return err
504 }
505 }
506
507 return nil
508 }
509 }
510
511 return fmt.Errorf("'%s' expected a map, got '%s'", name, dataVal.Kind())
512 }
513
514 // Accumulate errors
515 errors := make([]string, 0)
516
517 for _, k := range dataVal.MapKeys() {
518 fieldName := fmt.Sprintf("%s[%s]", name, k)
519
520 // First decode the key into the proper type
521 currentKey := reflect.Indirect(reflect.New(valKeyType))
522 if err := d.decode(fieldName, k.Interface(), currentKey); err != nil {
523 errors = appendErrors(errors, err)
524 continue
525 }
526
527 // Next decode the data into the proper type
528 v := dataVal.MapIndex(k).Interface()
529 currentVal := reflect.Indirect(reflect.New(valElemType))
530 if err := d.decode(fieldName, v, currentVal); err != nil {
531 errors = appendErrors(errors, err)
532 continue
533 }
534
535 valMap.SetMapIndex(currentKey, currentVal)
536 }
537
538 // Set the built up map to the value
539 val.Set(valMap)
540
541 // If we had errors, return those
542 if len(errors) > 0 {
543 return &Error{errors}
544 }
545
546 return nil
547}
548
549func (d *Decoder) decodePtr(name string, data interface{}, val reflect.Value) error {
550 // Create an element of the concrete (non pointer) type and decode
551 // into that. Then set the value of the pointer to this type.
552 valType := val.Type()
553 valElemType := valType.Elem()
554
555 realVal := val
556 if realVal.IsNil() || d.config.ZeroFields {
557 realVal = reflect.New(valElemType)
558 }
559
560 if err := d.decode(name, data, reflect.Indirect(realVal)); err != nil {
561 return err
562 }
563
564 val.Set(realVal)
565 return nil
566}
567
568func (d *Decoder) decodeFunc(name string, data interface{}, val reflect.Value) error {
569 // Create an element of the concrete (non pointer) type and decode
570 // into that. Then set the value of the pointer to this type.
571 dataVal := reflect.Indirect(reflect.ValueOf(data))
572 if val.Type() != dataVal.Type() {
573 return fmt.Errorf(
574 "'%s' expected type '%s', got unconvertible type '%s'",
575 name, val.Type(), dataVal.Type())
576 }
577 val.Set(dataVal)
578 return nil
579}
580
581func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value) error {
582 dataVal := reflect.Indirect(reflect.ValueOf(data))
583 dataValKind := dataVal.Kind()
584 valType := val.Type()
585 valElemType := valType.Elem()
586 sliceType := reflect.SliceOf(valElemType)
587
588 valSlice := val
589 if valSlice.IsNil() || d.config.ZeroFields {
590 // Check input type
591 if dataValKind != reflect.Array && dataValKind != reflect.Slice {
592 if d.config.WeaklyTypedInput {
593 switch {
594 // Empty maps turn into empty slices
595 case dataValKind == reflect.Map:
596 if dataVal.Len() == 0 {
597 val.Set(reflect.MakeSlice(sliceType, 0, 0))
598 return nil
599 }
600
601 // All other types we try to convert to the slice type
602 // and "lift" it into it. i.e. a string becomes a string slice.
603 default:
604 // Just re-try this function with data as a slice.
605 return d.decodeSlice(name, []interface{}{data}, val)
606 }
607 }
608
609 return fmt.Errorf(
610 "'%s': source data must be an array or slice, got %s", name, dataValKind)
611
612 }
613
614 // Make a new slice to hold our result, same size as the original data.
615 valSlice = reflect.MakeSlice(sliceType, dataVal.Len(), dataVal.Len())
616 }
617
618 // Accumulate any errors
619 errors := make([]string, 0)
620
621 for i := 0; i < dataVal.Len(); i++ {
622 currentData := dataVal.Index(i).Interface()
623 for valSlice.Len() <= i {
624 valSlice = reflect.Append(valSlice, reflect.Zero(valElemType))
625 }
626 currentField := valSlice.Index(i)
627
628 fieldName := fmt.Sprintf("%s[%d]", name, i)
629 if err := d.decode(fieldName, currentData, currentField); err != nil {
630 errors = appendErrors(errors, err)
631 }
632 }
633
634 // Finally, set the value to the slice we built up
635 val.Set(valSlice)
636
637 // If there were errors, we return those
638 if len(errors) > 0 {
639 return &Error{errors}
640 }
641
642 return nil
643}
644
645func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value) error {
646 dataVal := reflect.Indirect(reflect.ValueOf(data))
647
648 // If the type of the value to write to and the data match directly,
649 // then we just set it directly instead of recursing into the structure.
650 if dataVal.Type() == val.Type() {
651 val.Set(dataVal)
652 return nil
653 }
654
655 dataValKind := dataVal.Kind()
656 if dataValKind != reflect.Map {
657 return fmt.Errorf("'%s' expected a map, got '%s'", name, dataValKind)
658 }
659
660 dataValType := dataVal.Type()
661 if kind := dataValType.Key().Kind(); kind != reflect.String && kind != reflect.Interface {
662 return fmt.Errorf(
663 "'%s' needs a map with string keys, has '%s' keys",
664 name, dataValType.Key().Kind())
665 }
666
667 dataValKeys := make(map[reflect.Value]struct{})
668 dataValKeysUnused := make(map[interface{}]struct{})
669 for _, dataValKey := range dataVal.MapKeys() {
670 dataValKeys[dataValKey] = struct{}{}
671 dataValKeysUnused[dataValKey.Interface()] = struct{}{}
672 }
673
674 errors := make([]string, 0)
675
676 // This slice will keep track of all the structs we'll be decoding.
677 // There can be more than one struct if there are embedded structs
678 // that are squashed.
679 structs := make([]reflect.Value, 1, 5)
680 structs[0] = val
681
682 // Compile the list of all the fields that we're going to be decoding
683 // from all the structs.
684 fields := make(map[*reflect.StructField]reflect.Value)
685 for len(structs) > 0 {
686 structVal := structs[0]
687 structs = structs[1:]
688
689 structType := structVal.Type()
690
691 for i := 0; i < structType.NumField(); i++ {
692 fieldType := structType.Field(i)
693 fieldKind := fieldType.Type.Kind()
694
695 // If "squash" is specified in the tag, we squash the field down.
696 squash := false
697 tagParts := strings.Split(fieldType.Tag.Get(d.config.TagName), ",")
698 for _, tag := range tagParts[1:] {
699 if tag == "squash" {
700 squash = true
701 break
702 }
703 }
704
705 if squash {
706 if fieldKind != reflect.Struct {
707 errors = appendErrors(errors,
708 fmt.Errorf("%s: unsupported type for squash: %s", fieldType.Name, fieldKind))
709 } else {
710 structs = append(structs, val.FieldByName(fieldType.Name))
711 }
712 continue
713 }
714
715 // Normal struct field, store it away
716 fields[&fieldType] = structVal.Field(i)
717 }
718 }
719
720 for fieldType, field := range fields {
721 fieldName := fieldType.Name
722
723 tagValue := fieldType.Tag.Get(d.config.TagName)
724 tagValue = strings.SplitN(tagValue, ",", 2)[0]
725 if tagValue != "" {
726 fieldName = tagValue
727 }
728
729 rawMapKey := reflect.ValueOf(fieldName)
730 rawMapVal := dataVal.MapIndex(rawMapKey)
731 if !rawMapVal.IsValid() {
732 // Do a slower search by iterating over each key and
733 // doing case-insensitive search.
734 for dataValKey := range dataValKeys {
735 mK, ok := dataValKey.Interface().(string)
736 if !ok {
737 // Not a string key
738 continue
739 }
740
741 if strings.EqualFold(mK, fieldName) {
742 rawMapKey = dataValKey
743 rawMapVal = dataVal.MapIndex(dataValKey)
744 break
745 }
746 }
747
748 if !rawMapVal.IsValid() {
749 // There was no matching key in the map for the value in
750 // the struct. Just ignore.
751 continue
752 }
753 }
754
755 // Delete the key we're using from the unused map so we stop tracking
756 delete(dataValKeysUnused, rawMapKey.Interface())
757
758 if !field.IsValid() {
759 // This should never happen
760 panic("field is not valid")
761 }
762
763 // If we can't set the field, then it is unexported or something,
764 // and we just continue onwards.
765 if !field.CanSet() {
766 continue
767 }
768
769 // If the name is empty string, then we're at the root, and we
770 // don't dot-join the fields.
771 if name != "" {
772 fieldName = fmt.Sprintf("%s.%s", name, fieldName)
773 }
774
775 if err := d.decode(fieldName, rawMapVal.Interface(), field); err != nil {
776 errors = appendErrors(errors, err)
777 }
778 }
779
780 if d.config.ErrorUnused && len(dataValKeysUnused) > 0 {
781 keys := make([]string, 0, len(dataValKeysUnused))
782 for rawKey := range dataValKeysUnused {
783 keys = append(keys, rawKey.(string))
784 }
785 sort.Strings(keys)
786
787 err := fmt.Errorf("'%s' has invalid keys: %s", name, strings.Join(keys, ", "))
788 errors = appendErrors(errors, err)
789 }
790
791 if len(errors) > 0 {
792 return &Error{errors}
793 }
794
795 // Add the unused keys to the list of unused keys if we're tracking metadata
796 if d.config.Metadata != nil {
797 for rawKey := range dataValKeysUnused {
798 key := rawKey.(string)
799 if name != "" {
800 key = fmt.Sprintf("%s.%s", name, key)
801 }
802
803 d.config.Metadata.Unused = append(d.config.Metadata.Unused, key)
804 }
805 }
806
807 return nil
808}
809
810func getKind(val reflect.Value) reflect.Kind {
811 kind := val.Kind()
812
813 switch {
814 case kind >= reflect.Int && kind <= reflect.Int64:
815 return reflect.Int
816 case kind >= reflect.Uint && kind <= reflect.Uint64:
817 return reflect.Uint
818 case kind >= reflect.Float32 && kind <= reflect.Float64:
819 return reflect.Float32
820 default:
821 return kind
822 }
823}