OSDN Git Service

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