1 package toml
2
3 import (
4 "fmt"
5 "reflect"
6 "time"
7 )
8
9 var kindToType = [reflect.String + 1]reflect.Type{
10 reflect.Bool: reflect.TypeOf(true),
11 reflect.String: reflect.TypeOf(""),
12 reflect.Float32: reflect.TypeOf(float64(1)),
13 reflect.Float64: reflect.TypeOf(float64(1)),
14 reflect.Int: reflect.TypeOf(int64(1)),
15 reflect.Int8: reflect.TypeOf(int64(1)),
16 reflect.Int16: reflect.TypeOf(int64(1)),
17 reflect.Int32: reflect.TypeOf(int64(1)),
18 reflect.Int64: reflect.TypeOf(int64(1)),
19 reflect.Uint: reflect.TypeOf(uint64(1)),
20 reflect.Uint8: reflect.TypeOf(uint64(1)),
21 reflect.Uint16: reflect.TypeOf(uint64(1)),
22 reflect.Uint32: reflect.TypeOf(uint64(1)),
23 reflect.Uint64: reflect.TypeOf(uint64(1)),
24 }
25
26
27
28
29 func typeFor(k reflect.Kind) reflect.Type {
30 if k > 0 && int(k) < len(kindToType) {
31 return kindToType[k]
32 }
33 return nil
34 }
35
36 func simpleValueCoercion(object interface{}) (interface{}, error) {
37 switch original := object.(type) {
38 case string, bool, int64, uint64, float64, time.Time:
39 return original, nil
40 case int:
41 return int64(original), nil
42 case int8:
43 return int64(original), nil
44 case int16:
45 return int64(original), nil
46 case int32:
47 return int64(original), nil
48 case uint:
49 return uint64(original), nil
50 case uint8:
51 return uint64(original), nil
52 case uint16:
53 return uint64(original), nil
54 case uint32:
55 return uint64(original), nil
56 case float32:
57 return float64(original), nil
58 case fmt.Stringer:
59 return original.String(), nil
60 case []interface{}:
61 value := reflect.ValueOf(original)
62 length := value.Len()
63 arrayValue := reflect.MakeSlice(value.Type(), 0, length)
64 for i := 0; i < length; i++ {
65 val := value.Index(i).Interface()
66 simpleValue, err := simpleValueCoercion(val)
67 if err != nil {
68 return nil, err
69 }
70 arrayValue = reflect.Append(arrayValue, reflect.ValueOf(simpleValue))
71 }
72 return arrayValue.Interface(), nil
73 default:
74 return nil, fmt.Errorf("cannot convert type %T to Tree", object)
75 }
76 }
77
78 func sliceToTree(object interface{}) (interface{}, error) {
79
80
81
82
83
84
85 value := reflect.ValueOf(object)
86 insideType := value.Type().Elem()
87 length := value.Len()
88 if length > 0 {
89 insideType = reflect.ValueOf(value.Index(0).Interface()).Type()
90 }
91 if insideType.Kind() == reflect.Map {
92
93 tablesArray := make([]*Tree, 0, length)
94 for i := 0; i < length; i++ {
95 table := value.Index(i)
96 tree, err := toTree(table.Interface())
97 if err != nil {
98 return nil, err
99 }
100 tablesArray = append(tablesArray, tree.(*Tree))
101 }
102 return tablesArray, nil
103 }
104
105 sliceType := typeFor(insideType.Kind())
106 if sliceType == nil {
107 sliceType = insideType
108 }
109
110 arrayValue := reflect.MakeSlice(reflect.SliceOf(sliceType), 0, length)
111
112 for i := 0; i < length; i++ {
113 val := value.Index(i).Interface()
114 simpleValue, err := simpleValueCoercion(val)
115 if err != nil {
116 return nil, err
117 }
118 arrayValue = reflect.Append(arrayValue, reflect.ValueOf(simpleValue))
119 }
120 return &tomlValue{value: arrayValue.Interface(), position: Position{}}, nil
121 }
122
123 func toTree(object interface{}) (interface{}, error) {
124 value := reflect.ValueOf(object)
125
126 if value.Kind() == reflect.Map {
127 values := map[string]interface{}{}
128 keys := value.MapKeys()
129 for _, key := range keys {
130 if key.Kind() != reflect.String {
131 if _, ok := key.Interface().(string); !ok {
132 return nil, fmt.Errorf("map key needs to be a string, not %T (%v)", key.Interface(), key.Kind())
133 }
134 }
135
136 v := value.MapIndex(key)
137 newValue, err := toTree(v.Interface())
138 if err != nil {
139 return nil, err
140 }
141 values[key.String()] = newValue
142 }
143 return &Tree{values: values, position: Position{}}, nil
144 }
145
146 if value.Kind() == reflect.Array || value.Kind() == reflect.Slice {
147 return sliceToTree(object)
148 }
149
150 simpleValue, err := simpleValueCoercion(object)
151 if err != nil {
152 return nil, err
153 }
154 return &tomlValue{value: simpleValue, position: Position{}}, nil
155 }
156
View as plain text