yamlunmarshaler.go 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  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 = errors.New("only map-like configs are suported")
  13. yamlUnmarshaler = NewUnmarshaler(yamlTagKey)
  14. )
  15. func UnmarshalYamlBytes(content []byte, v interface{}) error {
  16. return unmarshalYamlBytes(content, v, yamlUnmarshaler)
  17. }
  18. func UnmarshalYamlReader(reader io.Reader, v interface{}) error {
  19. return unmarshalYamlReader(reader, v, yamlUnmarshaler)
  20. }
  21. func unmarshalYamlBytes(content []byte, v interface{}, unmarshaler *Unmarshaler) error {
  22. var o interface{}
  23. if err := yamlUnmarshal(content, &o); err != nil {
  24. return err
  25. }
  26. if m, ok := o.(map[string]interface{}); ok {
  27. return unmarshaler.Unmarshal(m, v)
  28. } else {
  29. return ErrUnsupportedType
  30. }
  31. }
  32. func unmarshalYamlReader(reader io.Reader, v interface{}, unmarshaler *Unmarshaler) error {
  33. content, err := ioutil.ReadAll(reader)
  34. if err != nil {
  35. return err
  36. }
  37. return unmarshalYamlBytes(content, v, unmarshaler)
  38. }
  39. // yamlUnmarshal YAML to map[string]interface{} instead of map[interface{}]interface{}.
  40. func yamlUnmarshal(in []byte, out interface{}) error {
  41. var res interface{}
  42. if err := yaml.Unmarshal(in, &res); err != nil {
  43. return err
  44. }
  45. *out.(*interface{}) = cleanupMapValue(res)
  46. return nil
  47. }
  48. func cleanupInterfaceMap(in map[interface{}]interface{}) map[string]interface{} {
  49. res := make(map[string]interface{})
  50. for k, v := range in {
  51. res[Repr(k)] = cleanupMapValue(v)
  52. }
  53. return res
  54. }
  55. func cleanupInterfaceNumber(in interface{}) json.Number {
  56. return json.Number(Repr(in))
  57. }
  58. func cleanupInterfaceSlice(in []interface{}) []interface{} {
  59. res := make([]interface{}, len(in))
  60. for i, v := range in {
  61. res[i] = cleanupMapValue(v)
  62. }
  63. return res
  64. }
  65. func cleanupMapValue(v interface{}) interface{} {
  66. switch v := v.(type) {
  67. case []interface{}:
  68. return cleanupInterfaceSlice(v)
  69. case map[interface{}]interface{}:
  70. return cleanupInterfaceMap(v)
  71. case bool, string:
  72. return v
  73. case int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64, float32, float64:
  74. return cleanupInterfaceNumber(v)
  75. default:
  76. return Repr(v)
  77. }
  78. }