tomltree_create.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. package toml
  2. import (
  3. "fmt"
  4. "reflect"
  5. "time"
  6. )
  7. var kindToType = [reflect.String + 1]reflect.Type{
  8. reflect.Bool: reflect.TypeOf(true),
  9. reflect.String: reflect.TypeOf(""),
  10. reflect.Float32: reflect.TypeOf(float64(1)),
  11. reflect.Float64: reflect.TypeOf(float64(1)),
  12. reflect.Int: reflect.TypeOf(int64(1)),
  13. reflect.Int8: reflect.TypeOf(int64(1)),
  14. reflect.Int16: reflect.TypeOf(int64(1)),
  15. reflect.Int32: reflect.TypeOf(int64(1)),
  16. reflect.Int64: reflect.TypeOf(int64(1)),
  17. reflect.Uint: reflect.TypeOf(uint64(1)),
  18. reflect.Uint8: reflect.TypeOf(uint64(1)),
  19. reflect.Uint16: reflect.TypeOf(uint64(1)),
  20. reflect.Uint32: reflect.TypeOf(uint64(1)),
  21. reflect.Uint64: reflect.TypeOf(uint64(1)),
  22. }
  23. // typeFor returns a reflect.Type for a reflect.Kind, or nil if none is found.
  24. // supported values:
  25. // string, bool, int64, uint64, float64, time.Time, int, int8, int16, int32, uint, uint8, uint16, uint32, float32
  26. func typeFor(k reflect.Kind) reflect.Type {
  27. if k > 0 && int(k) < len(kindToType) {
  28. return kindToType[k]
  29. }
  30. return nil
  31. }
  32. func simpleValueCoercion(object interface{}) (interface{}, error) {
  33. switch original := object.(type) {
  34. case string, bool, int64, uint64, float64, time.Time:
  35. return original, nil
  36. case int:
  37. return int64(original), nil
  38. case int8:
  39. return int64(original), nil
  40. case int16:
  41. return int64(original), nil
  42. case int32:
  43. return int64(original), nil
  44. case uint:
  45. return uint64(original), nil
  46. case uint8:
  47. return uint64(original), nil
  48. case uint16:
  49. return uint64(original), nil
  50. case uint32:
  51. return uint64(original), nil
  52. case float32:
  53. return float64(original), nil
  54. case fmt.Stringer:
  55. return original.String(), nil
  56. default:
  57. return nil, fmt.Errorf("cannot convert type %T to Tree", object)
  58. }
  59. }
  60. func sliceToTree(object interface{}) (interface{}, error) {
  61. // arrays are a bit tricky, since they can represent either a
  62. // collection of simple values, which is represented by one
  63. // *tomlValue, or an array of tables, which is represented by an
  64. // array of *Tree.
  65. // holding the assumption that this function is called from toTree only when value.Kind() is Array or Slice
  66. value := reflect.ValueOf(object)
  67. insideType := value.Type().Elem()
  68. length := value.Len()
  69. if length > 0 {
  70. insideType = reflect.ValueOf(value.Index(0).Interface()).Type()
  71. }
  72. if insideType.Kind() == reflect.Map {
  73. // this is considered as an array of tables
  74. tablesArray := make([]*Tree, 0, length)
  75. for i := 0; i < length; i++ {
  76. table := value.Index(i)
  77. tree, err := toTree(table.Interface())
  78. if err != nil {
  79. return nil, err
  80. }
  81. tablesArray = append(tablesArray, tree.(*Tree))
  82. }
  83. return tablesArray, nil
  84. }
  85. sliceType := typeFor(insideType.Kind())
  86. if sliceType == nil {
  87. sliceType = insideType
  88. }
  89. arrayValue := reflect.MakeSlice(reflect.SliceOf(sliceType), 0, length)
  90. for i := 0; i < length; i++ {
  91. val := value.Index(i).Interface()
  92. simpleValue, err := simpleValueCoercion(val)
  93. if err != nil {
  94. return nil, err
  95. }
  96. arrayValue = reflect.Append(arrayValue, reflect.ValueOf(simpleValue))
  97. }
  98. return &tomlValue{value: arrayValue.Interface(), position: Position{}}, nil
  99. }
  100. func toTree(object interface{}) (interface{}, error) {
  101. value := reflect.ValueOf(object)
  102. if value.Kind() == reflect.Map {
  103. values := map[string]interface{}{}
  104. keys := value.MapKeys()
  105. for _, key := range keys {
  106. if key.Kind() != reflect.String {
  107. if _, ok := key.Interface().(string); !ok {
  108. return nil, fmt.Errorf("map key needs to be a string, not %T (%v)", key.Interface(), key.Kind())
  109. }
  110. }
  111. v := value.MapIndex(key)
  112. newValue, err := toTree(v.Interface())
  113. if err != nil {
  114. return nil, err
  115. }
  116. values[key.String()] = newValue
  117. }
  118. return &Tree{values: values, position: Position{}}, nil
  119. }
  120. if value.Kind() == reflect.Array || value.Kind() == reflect.Slice {
  121. return sliceToTree(object)
  122. }
  123. simpleValue, err := simpleValueCoercion(object)
  124. if err != nil {
  125. return nil, err
  126. }
  127. return &tomlValue{value: simpleValue, position: Position{}}, nil
  128. }