OSDN Git Service

Hulk did something
[bytom/vapor.git] / vendor / github.com / pelletier / go-toml / toml.go
1 package toml
2
3 import (
4         "errors"
5         "fmt"
6         "io"
7         "io/ioutil"
8         "os"
9         "runtime"
10         "strings"
11 )
12
13 type tomlValue struct {
14         value     interface{} // string, int64, uint64, float64, bool, time.Time, [] of any of this list
15         comment   string
16         commented bool
17         position  Position
18 }
19
20 // Tree is the result of the parsing of a TOML file.
21 type Tree struct {
22         values    map[string]interface{} // string -> *tomlValue, *Tree, []*Tree
23         comment   string
24         commented bool
25         position  Position
26 }
27
28 func newTree() *Tree {
29         return &Tree{
30                 values:   make(map[string]interface{}),
31                 position: Position{},
32         }
33 }
34
35 // TreeFromMap initializes a new Tree object using the given map.
36 func TreeFromMap(m map[string]interface{}) (*Tree, error) {
37         result, err := toTree(m)
38         if err != nil {
39                 return nil, err
40         }
41         return result.(*Tree), nil
42 }
43
44 // Position returns the position of the tree.
45 func (t *Tree) Position() Position {
46         return t.position
47 }
48
49 // Has returns a boolean indicating if the given key exists.
50 func (t *Tree) Has(key string) bool {
51         if key == "" {
52                 return false
53         }
54         return t.HasPath(strings.Split(key, "."))
55 }
56
57 // HasPath returns true if the given path of keys exists, false otherwise.
58 func (t *Tree) HasPath(keys []string) bool {
59         return t.GetPath(keys) != nil
60 }
61
62 // Keys returns the keys of the toplevel tree (does not recurse).
63 func (t *Tree) Keys() []string {
64         keys := make([]string, len(t.values))
65         i := 0
66         for k := range t.values {
67                 keys[i] = k
68                 i++
69         }
70         return keys
71 }
72
73 // Get the value at key in the Tree.
74 // Key is a dot-separated path (e.g. a.b.c).
75 // Returns nil if the path does not exist in the tree.
76 // If keys is of length zero, the current tree is returned.
77 func (t *Tree) Get(key string) interface{} {
78         if key == "" {
79                 return t
80         }
81         comps, err := parseKey(key)
82         if err != nil {
83                 return nil
84         }
85         return t.GetPath(comps)
86 }
87
88 // GetPath returns the element in the tree indicated by 'keys'.
89 // If keys is of length zero, the current tree is returned.
90 func (t *Tree) GetPath(keys []string) interface{} {
91         if len(keys) == 0 {
92                 return t
93         }
94         subtree := t
95         for _, intermediateKey := range keys[:len(keys)-1] {
96                 value, exists := subtree.values[intermediateKey]
97                 if !exists {
98                         return nil
99                 }
100                 switch node := value.(type) {
101                 case *Tree:
102                         subtree = node
103                 case []*Tree:
104                         // go to most recent element
105                         if len(node) == 0 {
106                                 return nil
107                         }
108                         subtree = node[len(node)-1]
109                 default:
110                         return nil // cannot navigate through other node types
111                 }
112         }
113         // branch based on final node type
114         switch node := subtree.values[keys[len(keys)-1]].(type) {
115         case *tomlValue:
116                 return node.value
117         default:
118                 return node
119         }
120 }
121
122 // GetPosition returns the position of the given key.
123 func (t *Tree) GetPosition(key string) Position {
124         if key == "" {
125                 return t.position
126         }
127         return t.GetPositionPath(strings.Split(key, "."))
128 }
129
130 // GetPositionPath returns the element in the tree indicated by 'keys'.
131 // If keys is of length zero, the current tree is returned.
132 func (t *Tree) GetPositionPath(keys []string) Position {
133         if len(keys) == 0 {
134                 return t.position
135         }
136         subtree := t
137         for _, intermediateKey := range keys[:len(keys)-1] {
138                 value, exists := subtree.values[intermediateKey]
139                 if !exists {
140                         return Position{0, 0}
141                 }
142                 switch node := value.(type) {
143                 case *Tree:
144                         subtree = node
145                 case []*Tree:
146                         // go to most recent element
147                         if len(node) == 0 {
148                                 return Position{0, 0}
149                         }
150                         subtree = node[len(node)-1]
151                 default:
152                         return Position{0, 0}
153                 }
154         }
155         // branch based on final node type
156         switch node := subtree.values[keys[len(keys)-1]].(type) {
157         case *tomlValue:
158                 return node.position
159         case *Tree:
160                 return node.position
161         case []*Tree:
162                 // go to most recent element
163                 if len(node) == 0 {
164                         return Position{0, 0}
165                 }
166                 return node[len(node)-1].position
167         default:
168                 return Position{0, 0}
169         }
170 }
171
172 // GetDefault works like Get but with a default value
173 func (t *Tree) GetDefault(key string, def interface{}) interface{} {
174         val := t.Get(key)
175         if val == nil {
176                 return def
177         }
178         return val
179 }
180
181 // Set an element in the tree.
182 // Key is a dot-separated path (e.g. a.b.c).
183 // Creates all necessary intermediate trees, if needed.
184 func (t *Tree) Set(key string, comment string, commented bool, value interface{}) {
185         t.SetPath(strings.Split(key, "."), comment, commented, value)
186 }
187
188 // SetPath sets an element in the tree.
189 // Keys is an array of path elements (e.g. {"a","b","c"}).
190 // Creates all necessary intermediate trees, if needed.
191 func (t *Tree) SetPath(keys []string, comment string, commented bool, value interface{}) {
192         subtree := t
193         for _, intermediateKey := range keys[:len(keys)-1] {
194                 nextTree, exists := subtree.values[intermediateKey]
195                 if !exists {
196                         nextTree = newTree()
197                         subtree.values[intermediateKey] = nextTree // add new element here
198                 }
199                 switch node := nextTree.(type) {
200                 case *Tree:
201                         subtree = node
202                 case []*Tree:
203                         // go to most recent element
204                         if len(node) == 0 {
205                                 // create element if it does not exist
206                                 subtree.values[intermediateKey] = append(node, newTree())
207                         }
208                         subtree = node[len(node)-1]
209                 }
210         }
211
212         var toInsert interface{}
213
214         switch value.(type) {
215         case *Tree:
216                 tt := value.(*Tree)
217                 tt.comment = comment
218                 toInsert = value
219         case []*Tree:
220                 toInsert = value
221         case *tomlValue:
222                 tt := value.(*tomlValue)
223                 tt.comment = comment
224                 toInsert = tt
225         default:
226                 toInsert = &tomlValue{value: value, comment: comment, commented: commented}
227         }
228
229         subtree.values[keys[len(keys)-1]] = toInsert
230 }
231
232 // createSubTree takes a tree and a key and create the necessary intermediate
233 // subtrees to create a subtree at that point. In-place.
234 //
235 // e.g. passing a.b.c will create (assuming tree is empty) tree[a], tree[a][b]
236 // and tree[a][b][c]
237 //
238 // Returns nil on success, error object on failure
239 func (t *Tree) createSubTree(keys []string, pos Position) error {
240         subtree := t
241         for _, intermediateKey := range keys {
242                 nextTree, exists := subtree.values[intermediateKey]
243                 if !exists {
244                         tree := newTree()
245                         tree.position = pos
246                         subtree.values[intermediateKey] = tree
247                         nextTree = tree
248                 }
249
250                 switch node := nextTree.(type) {
251                 case []*Tree:
252                         subtree = node[len(node)-1]
253                 case *Tree:
254                         subtree = node
255                 default:
256                         return fmt.Errorf("unknown type for path %s (%s): %T (%#v)",
257                                 strings.Join(keys, "."), intermediateKey, nextTree, nextTree)
258                 }
259         }
260         return nil
261 }
262
263 // LoadBytes creates a Tree from a []byte.
264 func LoadBytes(b []byte) (tree *Tree, err error) {
265         defer func() {
266                 if r := recover(); r != nil {
267                         if _, ok := r.(runtime.Error); ok {
268                                 panic(r)
269                         }
270                         err = errors.New(r.(string))
271                 }
272         }()
273         tree = parseToml(lexToml(b))
274         return
275 }
276
277 // LoadReader creates a Tree from any io.Reader.
278 func LoadReader(reader io.Reader) (tree *Tree, err error) {
279         inputBytes, err := ioutil.ReadAll(reader)
280         if err != nil {
281                 return
282         }
283         tree, err = LoadBytes(inputBytes)
284         return
285 }
286
287 // Load creates a Tree from a string.
288 func Load(content string) (tree *Tree, err error) {
289         return LoadBytes([]byte(content))
290 }
291
292 // LoadFile creates a Tree from a file.
293 func LoadFile(path string) (tree *Tree, err error) {
294         file, err := os.Open(path)
295         if err != nil {
296                 return nil, err
297         }
298         defer file.Close()
299         return LoadReader(file)
300 }