]>
Commit | Line | Data |
---|---|---|
bae9f6d2 JC |
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 | } |