yamlunmarshaler.go 2.4 KB

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