You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

tomltree_create.go 4.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  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. case []interface{}:
  57. value := reflect.ValueOf(original)
  58. length := value.Len()
  59. arrayValue := reflect.MakeSlice(value.Type(), 0, length)
  60. for i := 0; i < length; i++ {
  61. val := value.Index(i).Interface()
  62. simpleValue, err := simpleValueCoercion(val)
  63. if err != nil {
  64. return nil, err
  65. }
  66. arrayValue = reflect.Append(arrayValue, reflect.ValueOf(simpleValue))
  67. }
  68. return arrayValue.Interface(), nil
  69. default:
  70. return nil, fmt.Errorf("cannot convert type %T to Tree", object)
  71. }
  72. }
  73. func sliceToTree(object interface{}) (interface{}, error) {
  74. // arrays are a bit tricky, since they can represent either a
  75. // collection of simple values, which is represented by one
  76. // *tomlValue, or an array of tables, which is represented by an
  77. // array of *Tree.
  78. // holding the assumption that this function is called from toTree only when value.Kind() is Array or Slice
  79. value := reflect.ValueOf(object)
  80. insideType := value.Type().Elem()
  81. length := value.Len()
  82. if length > 0 {
  83. insideType = reflect.ValueOf(value.Index(0).Interface()).Type()
  84. }
  85. if insideType.Kind() == reflect.Map {
  86. // this is considered as an array of tables
  87. tablesArray := make([]*Tree, 0, length)
  88. for i := 0; i < length; i++ {
  89. table := value.Index(i)
  90. tree, err := toTree(table.Interface())
  91. if err != nil {
  92. return nil, err
  93. }
  94. tablesArray = append(tablesArray, tree.(*Tree))
  95. }
  96. return tablesArray, nil
  97. }
  98. sliceType := typeFor(insideType.Kind())
  99. if sliceType == nil {
  100. sliceType = insideType
  101. }
  102. arrayValue := reflect.MakeSlice(reflect.SliceOf(sliceType), 0, length)
  103. for i := 0; i < length; i++ {
  104. val := value.Index(i).Interface()
  105. simpleValue, err := simpleValueCoercion(val)
  106. if err != nil {
  107. return nil, err
  108. }
  109. arrayValue = reflect.Append(arrayValue, reflect.ValueOf(simpleValue))
  110. }
  111. return &tomlValue{value: arrayValue.Interface(), position: Position{}}, nil
  112. }
  113. func toTree(object interface{}) (interface{}, error) {
  114. value := reflect.ValueOf(object)
  115. if value.Kind() == reflect.Map {
  116. values := map[string]interface{}{}
  117. keys := value.MapKeys()
  118. for _, key := range keys {
  119. if key.Kind() != reflect.String {
  120. if _, ok := key.Interface().(string); !ok {
  121. return nil, fmt.Errorf("map key needs to be a string, not %T (%v)", key.Interface(), key.Kind())
  122. }
  123. }
  124. v := value.MapIndex(key)
  125. newValue, err := toTree(v.Interface())
  126. if err != nil {
  127. return nil, err
  128. }
  129. values[key.String()] = newValue
  130. }
  131. return &Tree{values: values, position: Position{}}, nil
  132. }
  133. if value.Kind() == reflect.Array || value.Kind() == reflect.Slice {
  134. return sliceToTree(object)
  135. }
  136. simpleValue, err := simpleValueCoercion(object)
  137. if err != nil {
  138. return nil, err
  139. }
  140. return &tomlValue{value: simpleValue, position: Position{}}, nil
  141. }