120 // |
120 // |
121 // For example, the zero type of a numeric type is zero ("0"). If the struct |
121 // For example, the zero type of a numeric type is zero ("0"). If the struct |
122 // field value is zero and a numeric type, the field is empty, and it won't |
122 // field value is zero and a numeric type, the field is empty, and it won't |
123 // be encoded into the destination type. |
123 // be encoded into the destination type. |
124 // |
124 // |
125 // type Source { |
125 // type Source struct { |
126 // Age int `mapstructure:",omitempty"` |
126 // Age int `mapstructure:",omitempty"` |
127 // } |
127 // } |
128 // |
128 // |
129 // Unexported fields |
129 // Unexported fields |
130 // |
130 // |
190 |
190 |
191 // DecodeHookFuncKind is a DecodeHookFunc which knows only the Kinds of the |
191 // DecodeHookFuncKind is a DecodeHookFunc which knows only the Kinds of the |
192 // source and target types. |
192 // source and target types. |
193 type DecodeHookFuncKind func(reflect.Kind, reflect.Kind, interface{}) (interface{}, error) |
193 type DecodeHookFuncKind func(reflect.Kind, reflect.Kind, interface{}) (interface{}, error) |
194 |
194 |
195 // DecodeHookFuncRaw is a DecodeHookFunc which has complete access to both the source and target |
195 // DecodeHookFuncValue is a DecodeHookFunc which has complete access to both the source and target |
196 // values. |
196 // values. |
197 type DecodeHookFuncValue func(from reflect.Value, to reflect.Value) (interface{}, error) |
197 type DecodeHookFuncValue func(from reflect.Value, to reflect.Value) (interface{}, error) |
198 |
198 |
199 // DecoderConfig is the configuration that is used to create a new decoder |
199 // DecoderConfig is the configuration that is used to create a new decoder |
200 // and allows customization of various aspects of decoding. |
200 // and allows customization of various aspects of decoding. |
212 |
212 |
213 // If ErrorUnused is true, then it is an error for there to exist |
213 // If ErrorUnused is true, then it is an error for there to exist |
214 // keys in the original map that were unused in the decoding process |
214 // keys in the original map that were unused in the decoding process |
215 // (extra keys). |
215 // (extra keys). |
216 ErrorUnused bool |
216 ErrorUnused bool |
|
217 |
|
218 // If ErrorUnset is true, then it is an error for there to exist |
|
219 // fields in the result that were not set in the decoding process |
|
220 // (extra fields). This only applies to decoding to a struct. This |
|
221 // will affect all nested structs as well. |
|
222 ErrorUnset bool |
217 |
223 |
218 // ZeroFields, if set to true, will zero fields before writing them. |
224 // ZeroFields, if set to true, will zero fields before writing them. |
219 // For example, a map will be emptied before decoded values are put in |
225 // For example, a map will be emptied before decoded values are put in |
220 // it. If this is false, a map will be merged. |
226 // it. If this is false, a map will be merged. |
221 ZeroFields bool |
227 ZeroFields bool |
256 Result interface{} |
262 Result interface{} |
257 |
263 |
258 // The tag name that mapstructure reads for field names. This |
264 // The tag name that mapstructure reads for field names. This |
259 // defaults to "mapstructure" |
265 // defaults to "mapstructure" |
260 TagName string |
266 TagName string |
|
267 |
|
268 // IgnoreUntaggedFields ignores all struct fields without explicit |
|
269 // TagName, comparable to `mapstructure:"-"` as default behaviour. |
|
270 IgnoreUntaggedFields bool |
|
271 |
|
272 // MatchName is the function used to match the map key to the struct |
|
273 // field name or tag. Defaults to `strings.EqualFold`. This can be used |
|
274 // to implement case-sensitive tag values, support snake casing, etc. |
|
275 MatchName func(mapKey, fieldName string) bool |
261 } |
276 } |
262 |
277 |
263 // A Decoder takes a raw interface value and turns it into structured |
278 // A Decoder takes a raw interface value and turns it into structured |
264 // data, keeping track of rich error information along the way in case |
279 // data, keeping track of rich error information along the way in case |
265 // anything goes wrong. Unlike the basic top-level Decode method, you can |
280 // anything goes wrong. Unlike the basic top-level Decode method, you can |
277 Keys []string |
292 Keys []string |
278 |
293 |
279 // Unused is a slice of keys that were found in the raw value but |
294 // Unused is a slice of keys that were found in the raw value but |
280 // weren't decoded since there was no matching field in the result interface |
295 // weren't decoded since there was no matching field in the result interface |
281 Unused []string |
296 Unused []string |
|
297 |
|
298 // Unset is a slice of field names that were found in the result interface |
|
299 // but weren't set in the decoding process since there was no matching value |
|
300 // in the input |
|
301 Unset []string |
282 } |
302 } |
283 |
303 |
284 // Decode takes an input structure and uses reflection to translate it to |
304 // Decode takes an input structure and uses reflection to translate it to |
285 // the output structure. output must be a pointer to a map or struct. |
305 // the output structure. output must be a pointer to a map or struct. |
286 func Decode(input interface{}, output interface{}) error { |
306 func Decode(input interface{}, output interface{}) error { |
368 } |
388 } |
369 |
389 |
370 if config.Metadata.Unused == nil { |
390 if config.Metadata.Unused == nil { |
371 config.Metadata.Unused = make([]string, 0) |
391 config.Metadata.Unused = make([]string, 0) |
372 } |
392 } |
|
393 |
|
394 if config.Metadata.Unset == nil { |
|
395 config.Metadata.Unset = make([]string, 0) |
|
396 } |
373 } |
397 } |
374 |
398 |
375 if config.TagName == "" { |
399 if config.TagName == "" { |
376 config.TagName = "mapstructure" |
400 config.TagName = "mapstructure" |
|
401 } |
|
402 |
|
403 if config.MatchName == nil { |
|
404 config.MatchName = strings.EqualFold |
377 } |
405 } |
378 |
406 |
379 result := &Decoder{ |
407 result := &Decoder{ |
380 config: config, |
408 config: config, |
381 } |
409 } |
673 } else { |
701 } else { |
674 return fmt.Errorf("cannot parse '%s' as uint: %s", name, err) |
702 return fmt.Errorf("cannot parse '%s' as uint: %s", name, err) |
675 } |
703 } |
676 case dataType.PkgPath() == "encoding/json" && dataType.Name() == "Number": |
704 case dataType.PkgPath() == "encoding/json" && dataType.Name() == "Number": |
677 jn := data.(json.Number) |
705 jn := data.(json.Number) |
678 i, err := jn.Int64() |
706 i, err := strconv.ParseUint(string(jn), 0, 64) |
679 if err != nil { |
707 if err != nil { |
680 return fmt.Errorf( |
708 return fmt.Errorf( |
681 "error decoding json.Number into %s: %s", name, err) |
709 "error decoding json.Number into %s: %s", name, err) |
682 } |
710 } |
683 if i < 0 && !d.config.WeaklyTypedInput { |
711 val.SetUint(i) |
684 return fmt.Errorf("cannot parse '%s', %d overflows uint", |
|
685 name, i) |
|
686 } |
|
687 val.SetUint(uint64(i)) |
|
688 default: |
712 default: |
689 return fmt.Errorf( |
713 return fmt.Errorf( |
690 "'%s' expected type '%s', got unconvertible type '%s', value: '%v'", |
714 "'%s' expected type '%s', got unconvertible type '%s', value: '%v'", |
691 name, val.Type(), dataVal.Type(), data) |
715 name, val.Type(), dataVal.Type(), data) |
692 } |
716 } |
899 } |
923 } |
900 |
924 |
901 tagValue := f.Tag.Get(d.config.TagName) |
925 tagValue := f.Tag.Get(d.config.TagName) |
902 keyName := f.Name |
926 keyName := f.Name |
903 |
927 |
|
928 if tagValue == "" && d.config.IgnoreUntaggedFields { |
|
929 continue |
|
930 } |
|
931 |
904 // If Squash is set in the config, we squash the field down. |
932 // If Squash is set in the config, we squash the field down. |
905 squash := d.config.Squash && v.Kind() == reflect.Struct && f.Anonymous |
933 squash := d.config.Squash && v.Kind() == reflect.Struct && f.Anonymous |
|
934 |
|
935 v = dereferencePtrToStructIfNeeded(v, d.config.TagName) |
906 |
936 |
907 // Determine the name of the key in the map |
937 // Determine the name of the key in the map |
908 if index := strings.Index(tagValue, ","); index != -1 { |
938 if index := strings.Index(tagValue, ","); index != -1 { |
909 if tagValue[:index] == "-" { |
939 if tagValue[:index] == "-" { |
910 continue |
940 continue |
913 if strings.Index(tagValue[index+1:], "omitempty") != -1 && isEmptyValue(v) { |
943 if strings.Index(tagValue[index+1:], "omitempty") != -1 && isEmptyValue(v) { |
914 continue |
944 continue |
915 } |
945 } |
916 |
946 |
917 // If "squash" is specified in the tag, we squash the field down. |
947 // If "squash" is specified in the tag, we squash the field down. |
918 squash = !squash && strings.Index(tagValue[index+1:], "squash") != -1 |
948 squash = squash || strings.Index(tagValue[index+1:], "squash") != -1 |
919 if squash { |
949 if squash { |
920 // When squashing, the embedded type can be a pointer to a struct. |
950 // When squashing, the embedded type can be a pointer to a struct. |
921 if v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct { |
951 if v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct { |
922 v = v.Elem() |
952 v = v.Elem() |
923 } |
953 } |
925 // The final type must be a struct |
955 // The final type must be a struct |
926 if v.Kind() != reflect.Struct { |
956 if v.Kind() != reflect.Struct { |
927 return fmt.Errorf("cannot squash non-struct type '%s'", v.Type()) |
957 return fmt.Errorf("cannot squash non-struct type '%s'", v.Type()) |
928 } |
958 } |
929 } |
959 } |
930 keyName = tagValue[:index] |
960 if keyNameTagValue := tagValue[:index]; keyNameTagValue != "" { |
|
961 keyName = keyNameTagValue |
|
962 } |
931 } else if len(tagValue) > 0 { |
963 } else if len(tagValue) > 0 { |
932 if tagValue == "-" { |
964 if tagValue == "-" { |
933 continue |
965 continue |
934 } |
966 } |
935 keyName = tagValue |
967 keyName = tagValue |
1081 return fmt.Errorf( |
1113 return fmt.Errorf( |
1082 "'%s': source data must be an array or slice, got %s", name, dataValKind) |
1114 "'%s': source data must be an array or slice, got %s", name, dataValKind) |
1083 } |
1115 } |
1084 |
1116 |
1085 // If the input value is nil, then don't allocate since empty != nil |
1117 // If the input value is nil, then don't allocate since empty != nil |
1086 if dataVal.IsNil() { |
1118 if dataValKind != reflect.Array && dataVal.IsNil() { |
1087 return nil |
1119 return nil |
1088 } |
1120 } |
1089 |
1121 |
1090 valSlice := val |
1122 valSlice := val |
1091 if valSlice.IsNil() || d.config.ZeroFields { |
1123 if valSlice.IsNil() || d.config.ZeroFields { |
1243 for _, dataValKey := range dataVal.MapKeys() { |
1275 for _, dataValKey := range dataVal.MapKeys() { |
1244 dataValKeys[dataValKey] = struct{}{} |
1276 dataValKeys[dataValKey] = struct{}{} |
1245 dataValKeysUnused[dataValKey.Interface()] = struct{}{} |
1277 dataValKeysUnused[dataValKey.Interface()] = struct{}{} |
1246 } |
1278 } |
1247 |
1279 |
|
1280 targetValKeysUnused := make(map[interface{}]struct{}) |
1248 errors := make([]string, 0) |
1281 errors := make([]string, 0) |
1249 |
1282 |
1250 // This slice will keep track of all the structs we'll be decoding. |
1283 // This slice will keep track of all the structs we'll be decoding. |
1251 // There can be more than one struct if there are embedded structs |
1284 // There can be more than one struct if there are embedded structs |
1252 // that are squashed. |
1285 // that are squashed. |
1338 if !ok { |
1371 if !ok { |
1339 // Not a string key |
1372 // Not a string key |
1340 continue |
1373 continue |
1341 } |
1374 } |
1342 |
1375 |
1343 if strings.EqualFold(mK, fieldName) { |
1376 if d.config.MatchName(mK, fieldName) { |
1344 rawMapKey = dataValKey |
1377 rawMapKey = dataValKey |
1345 rawMapVal = dataVal.MapIndex(dataValKey) |
1378 rawMapVal = dataVal.MapIndex(dataValKey) |
1346 break |
1379 break |
1347 } |
1380 } |
1348 } |
1381 } |
1349 |
1382 |
1350 if !rawMapVal.IsValid() { |
1383 if !rawMapVal.IsValid() { |
1351 // There was no matching key in the map for the value in |
1384 // There was no matching key in the map for the value in |
1352 // the struct. Just ignore. |
1385 // the struct. Remember it for potential errors and metadata. |
|
1386 targetValKeysUnused[fieldName] = struct{}{} |
1353 continue |
1387 continue |
1354 } |
1388 } |
1355 } |
1389 } |
1356 |
1390 |
1357 if !fieldValue.IsValid() { |
1391 if !fieldValue.IsValid() { |
1407 |
1441 |
1408 err := fmt.Errorf("'%s' has invalid keys: %s", name, strings.Join(keys, ", ")) |
1442 err := fmt.Errorf("'%s' has invalid keys: %s", name, strings.Join(keys, ", ")) |
1409 errors = appendErrors(errors, err) |
1443 errors = appendErrors(errors, err) |
1410 } |
1444 } |
1411 |
1445 |
|
1446 if d.config.ErrorUnset && len(targetValKeysUnused) > 0 { |
|
1447 keys := make([]string, 0, len(targetValKeysUnused)) |
|
1448 for rawKey := range targetValKeysUnused { |
|
1449 keys = append(keys, rawKey.(string)) |
|
1450 } |
|
1451 sort.Strings(keys) |
|
1452 |
|
1453 err := fmt.Errorf("'%s' has unset fields: %s", name, strings.Join(keys, ", ")) |
|
1454 errors = appendErrors(errors, err) |
|
1455 } |
|
1456 |
1412 if len(errors) > 0 { |
1457 if len(errors) > 0 { |
1413 return &Error{errors} |
1458 return &Error{errors} |
1414 } |
1459 } |
1415 |
1460 |
1416 // Add the unused keys to the list of unused keys if we're tracking metadata |
1461 // Add the unused keys to the list of unused keys if we're tracking metadata |
1458 return reflect.Float32 |
1511 return reflect.Float32 |
1459 default: |
1512 default: |
1460 return kind |
1513 return kind |
1461 } |
1514 } |
1462 } |
1515 } |
|
1516 |
|
1517 func isStructTypeConvertibleToMap(typ reflect.Type, checkMapstructureTags bool, tagName string) bool { |
|
1518 for i := 0; i < typ.NumField(); i++ { |
|
1519 f := typ.Field(i) |
|
1520 if f.PkgPath == "" && !checkMapstructureTags { // check for unexported fields |
|
1521 return true |
|
1522 } |
|
1523 if checkMapstructureTags && f.Tag.Get(tagName) != "" { // check for mapstructure tags inside |
|
1524 return true |
|
1525 } |
|
1526 } |
|
1527 return false |
|
1528 } |
|
1529 |
|
1530 func dereferencePtrToStructIfNeeded(v reflect.Value, tagName string) reflect.Value { |
|
1531 if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct { |
|
1532 return v |
|
1533 } |
|
1534 deref := v.Elem() |
|
1535 derefT := deref.Type() |
|
1536 if isStructTypeConvertibleToMap(derefT, true, tagName) { |
|
1537 return deref |
|
1538 } |
|
1539 return v |
|
1540 } |