diff options
author | Jake Champlin <jake.champlin.27@gmail.com> | 2017-06-06 12:40:07 -0400 |
---|---|---|
committer | Jake Champlin <jake.champlin.27@gmail.com> | 2017-06-06 12:40:07 -0400 |
commit | bae9f6d2fd5eb5bc80929bd393932b23f14d7c93 (patch) | |
tree | ca9ab12a7d78b1fc27a8f734729081357ce6d252 /vendor/github.com/mitchellh/mapstructure | |
parent | 254c495b6bebab3fb72a243c4bce858d79e6ee99 (diff) | |
download | terraform-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/LICENSE | 21 | ||||
-rw-r--r-- | vendor/github.com/mitchellh/mapstructure/README.md | 46 | ||||
-rw-r--r-- | vendor/github.com/mitchellh/mapstructure/decode_hooks.go | 154 | ||||
-rw-r--r-- | vendor/github.com/mitchellh/mapstructure/error.go | 50 | ||||
-rw-r--r-- | vendor/github.com/mitchellh/mapstructure/mapstructure.go | 823 |
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 @@ | |||
1 | The MIT License (MIT) | ||
2 | |||
3 | Copyright (c) 2013 Mitchell Hashimoto | ||
4 | |||
5 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
6 | of this software and associated documentation files (the "Software"), to deal | ||
7 | in the Software without restriction, including without limitation the rights | ||
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
9 | copies of the Software, and to permit persons to whom the Software is | ||
10 | furnished to do so, subject to the following conditions: | ||
11 | |||
12 | The above copyright notice and this permission notice shall be included in | ||
13 | all copies or substantial portions of the Software. | ||
14 | |||
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
21 | THE 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 | |||
3 | mapstructure is a Go library for decoding generic map values to structures | ||
4 | and vice versa, while providing helpful error handling. | ||
5 | |||
6 | This library is most useful when decoding values from some data stream (JSON, | ||
7 | Gob, etc.) where you don't _quite_ know the structure of the underlying data | ||
8 | until you read a part of it. You can therefore read a `map[string]interface{}` | ||
9 | and use this library to decode it into the proper underlying native Go | ||
10 | structure. | ||
11 | |||
12 | ## Installation | ||
13 | |||
14 | Standard `go get`: | ||
15 | |||
16 | ``` | ||
17 | $ go get github.com/mitchellh/mapstructure | ||
18 | ``` | ||
19 | |||
20 | ## Usage & Example | ||
21 | |||
22 | For usage and examples see the [Godoc](http://godoc.org/github.com/mitchellh/mapstructure). | ||
23 | |||
24 | The `Decode` function has examples associated with it there. | ||
25 | |||
26 | ## But Why?! | ||
27 | |||
28 | Go offers fantastic standard libraries for decoding formats such as JSON. | ||
29 | The standard method is to have a struct pre-created, and populate that struct | ||
30 | from the bytes of the encoded format. This is great, but the problem is if | ||
31 | you have configuration or an encoding that changes slightly depending on | ||
32 | specific fields. For example, consider this JSON: | ||
33 | |||
34 | ```json | ||
35 | { | ||
36 | "type": "person", | ||
37 | "name": "Mitchell" | ||
38 | } | ||
39 | ``` | ||
40 | |||
41 | Perhaps we can't populate a specific structure without first reading | ||
42 | the "type" field from the JSON. We could always do two passes over the | ||
43 | decoding of the JSON (reading the "type" first, and the rest later). | ||
44 | However, it is much simpler to just decode this into a `map[string]interface{}` | ||
45 | structure, read the "type" key, then use something like this library | ||
46 | to 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 @@ | |||
1 | package mapstructure | ||
2 | |||
3 | import ( | ||
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. | ||
13 | func 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. | ||
37 | func 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. | ||
62 | func 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. | ||
87 | func 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. | ||
107 | func 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 | |||
124 | func 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 @@ | |||
1 | package mapstructure | ||
2 | |||
3 | import ( | ||
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. | ||
12 | type Error struct { | ||
13 | Errors []string | ||
14 | } | ||
15 | |||
16 | func (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. | ||
30 | func (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 | |||
43 | func 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. | ||
8 | package mapstructure | ||
9 | |||
10 | import ( | ||
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. | ||
33 | type DecodeHookFunc interface{} | ||
34 | |||
35 | type DecodeHookFuncType func(reflect.Type, reflect.Type, interface{}) (interface{}, error) | ||
36 | type 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. | ||
40 | type 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. | ||
97 | type Decoder struct { | ||
98 | config *DecoderConfig | ||
99 | } | ||
100 | |||
101 | // Metadata contains information about decoding a structure that | ||
102 | // is tedious or difficult to get otherwise. | ||
103 | type 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. | ||
114 | func 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. | ||
130 | func 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. | ||
148 | func 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. | ||
182 | func (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. | ||
187 | func (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. | ||
253 | func (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 | |||
270 | func (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 | |||
312 | func (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 | |||
354 | func (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 | |||
397 | func (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 | |||
428 | func (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 | |||
470 | func (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 | |||
549 | func (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 | |||
568 | func (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 | |||
581 | func (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 | |||
645 | func (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 | |||
810 | func 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 | } | ||