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 // typeFor returns a reflect.Type for a reflect.Kind, or nil if none is found. |
|
27 // supported values: |
|
28 // string, bool, int64, uint64, float64, time.Time, int, int8, int16, int32, uint, uint8, uint16, uint32, float32 |
|
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 // arrays are a bit tricky, since they can represent either a |
|
80 // collection of simple values, which is represented by one |
|
81 // *tomlValue, or an array of tables, which is represented by an |
|
82 // array of *Tree. |
|
83 |
|
84 // holding the assumption that this function is called from toTree only when value.Kind() is Array or Slice |
|
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 // this is considered as an array of tables |
|
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 } |
|