yamlunmarshaler.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. package mapping
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "io"
  6. "gopkg.in/yaml.v2"
  7. )
  8. // To make .json & .yaml consistent, we just use json as the tag key.
  9. const yamlTagKey = "json"
  10. var (
  11. // ErrUnsupportedType is an error that indicates the config format is not supported.
  12. ErrUnsupportedType = errors.New("only map-like configs are supported")
  13. yamlUnmarshaler = NewUnmarshaler(yamlTagKey)
  14. )
  15. // UnmarshalYamlBytes unmarshals content into v.
  16. func UnmarshalYamlBytes(content []byte, v interface{}) error {
  17. return unmarshalYamlBytes(content, v, yamlUnmarshaler)
  18. }
  19. // UnmarshalYamlReader unmarshals content from reader into v.
  20. func UnmarshalYamlReader(reader io.Reader, v interface{}) error {
  21. return unmarshalYamlReader(reader, v, yamlUnmarshaler)
  22. }
  23. func cleanupInterfaceMap(in map[interface{}]interface{}) map[string]interface{} {
  24. res := make(map[string]interface{})
  25. for k, v := range in {
  26. res[Repr(k)] = cleanupMapValue(v)
  27. }
  28. return res
  29. }
  30. func cleanupInterfaceNumber(in interface{}) json.Number {
  31. return json.Number(Repr(in))
  32. }
  33. func cleanupInterfaceSlice(in []interface{}) []interface{} {
  34. res := make([]interface{}, len(in))
  35. for i, v := range in {
  36. res[i] = cleanupMapValue(v)
  37. }
  38. return res
  39. }
  40. func cleanupMapValue(v interface{}) interface{} {
  41. switch v := v.(type) {
  42. case []interface{}:
  43. return cleanupInterfaceSlice(v)
  44. case map[interface{}]interface{}:
  45. return cleanupInterfaceMap(v)
  46. case bool, string:
  47. return v
  48. case int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64, float32, float64:
  49. return cleanupInterfaceNumber(v)
  50. default:
  51. return Repr(v)
  52. }
  53. }
  54. func unmarshal(unmarshaler *Unmarshaler, o interface{}, v interface{}) error {
  55. if m, ok := o.(map[string]interface{}); ok {
  56. return unmarshaler.Unmarshal(m, v)
  57. }
  58. return ErrUnsupportedType
  59. }
  60. func unmarshalYamlBytes(content []byte, v interface{}, unmarshaler *Unmarshaler) error {
  61. var o interface{}
  62. if err := yamlUnmarshal(content, &o); err != nil {
  63. return err
  64. }
  65. return unmarshal(unmarshaler, o, v)
  66. }
  67. func unmarshalYamlReader(reader io.Reader, v interface{}, unmarshaler *Unmarshaler) error {
  68. var res interface{}
  69. if err := yaml.NewDecoder(reader).Decode(&res); err != nil {
  70. return err
  71. }
  72. return unmarshal(unmarshaler, cleanupMapValue(res), v)
  73. }
  74. // yamlUnmarshal YAML to map[string]interface{} instead of map[interface{}]interface{}.
  75. func yamlUnmarshal(in []byte, out interface{}) error {
  76. var res interface{}
  77. if err := yaml.Unmarshal(in, &res); err != nil {
  78. return err
  79. }
  80. *out.(*interface{}) = cleanupMapValue(res)
  81. return nil
  82. }