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. }
  29. return ErrUnsupportedType
  30. }
  31. func unmarshalYamlReader(reader io.Reader, v interface{}, unmarshaler *Unmarshaler) error {
  32. content, err := ioutil.ReadAll(reader)
  33. if err != nil {
  34. return err
  35. }
  36. return unmarshalYamlBytes(content, v, unmarshaler)
  37. }
  38. // yamlUnmarshal YAML to map[string]interface{} instead of map[interface{}]interface{}.
  39. func yamlUnmarshal(in []byte, out interface{}) error {
  40. var res interface{}
  41. if err := yaml.Unmarshal(in, &res); err != nil {
  42. return err
  43. }
  44. *out.(*interface{}) = cleanupMapValue(res)
  45. return nil
  46. }
  47. func cleanupInterfaceMap(in map[interface{}]interface{}) map[string]interface{} {
  48. res := make(map[string]interface{})
  49. for k, v := range in {
  50. res[Repr(k)] = cleanupMapValue(v)
  51. }
  52. return res
  53. }
  54. func cleanupInterfaceNumber(in interface{}) json.Number {
  55. return json.Number(Repr(in))
  56. }
  57. func cleanupInterfaceSlice(in []interface{}) []interface{} {
  58. res := make([]interface{}, len(in))
  59. for i, v := range in {
  60. res[i] = cleanupMapValue(v)
  61. }
  62. return res
  63. }
  64. func cleanupMapValue(v interface{}) interface{} {
  65. switch v := v.(type) {
  66. case []interface{}:
  67. return cleanupInterfaceSlice(v)
  68. case map[interface{}]interface{}:
  69. return cleanupInterfaceMap(v)
  70. case bool, string:
  71. return v
  72. case int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64, float32, float64:
  73. return cleanupInterfaceNumber(v)
  74. default:
  75. return Repr(v)
  76. }
  77. }