yamlunmarshaler.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. package mapping
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "gopkg.in/yaml.v2"
  6. "io"
  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 suported")
  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 unmarshalYamlBytes(content []byte, v interface{}, unmarshaler *Unmarshaler) error {
  24. var o interface{}
  25. if err := yamlUnmarshal(content, &o); err != nil {
  26. return err
  27. }
  28. if m, ok := o.(map[string]interface{}); ok {
  29. return unmarshaler.Unmarshal(m, v)
  30. }
  31. return ErrUnsupportedType
  32. }
  33. func unmarshalYamlReader(reader io.Reader, v interface{}, unmarshaler *Unmarshaler) error {
  34. var res interface{}
  35. if err := yaml.NewDecoder(reader).Decode(&res); err != nil {
  36. return err
  37. }
  38. out := cleanupMapValue(res)
  39. if m, ok := out.(map[string]interface{}); ok {
  40. return unmarshaler.Unmarshal(m, v)
  41. }
  42. return ErrUnsupportedType
  43. }
  44. // yamlUnmarshal YAML to map[string]interface{} instead of map[interface{}]interface{}.
  45. func yamlUnmarshal(in []byte, out interface{}) error {
  46. var res interface{}
  47. if err := yaml.Unmarshal(in, &res); err != nil {
  48. return err
  49. }
  50. *out.(*interface{}) = cleanupMapValue(res)
  51. return nil
  52. }
  53. func cleanupInterfaceMap(in map[interface{}]interface{}) map[string]interface{} {
  54. res := make(map[string]interface{})
  55. for k, v := range in {
  56. res[Repr(k)] = cleanupMapValue(v)
  57. }
  58. return res
  59. }
  60. func cleanupInterfaceNumber(in interface{}) json.Number {
  61. return json.Number(Repr(in))
  62. }
  63. func cleanupInterfaceSlice(in []interface{}) []interface{} {
  64. res := make([]interface{}, len(in))
  65. for i, v := range in {
  66. res[i] = cleanupMapValue(v)
  67. }
  68. return res
  69. }
  70. func cleanupMapValue(v interface{}) interface{} {
  71. switch v := v.(type) {
  72. case []interface{}:
  73. return cleanupInterfaceSlice(v)
  74. case map[interface{}]interface{}:
  75. return cleanupInterfaceMap(v)
  76. case bool, string:
  77. return v
  78. case int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64, float32, float64:
  79. return cleanupInterfaceNumber(v)
  80. default:
  81. return Repr(v)
  82. }
  83. }