OSDN Git Service

Hulk did something
[bytom/vapor.git] / vendor / github.com / pelletier / go-toml / marshal.go
1 package toml
2
3 import (
4         "bytes"
5         "errors"
6         "fmt"
7         "io"
8         "reflect"
9         "strconv"
10         "strings"
11         "time"
12 )
13
14 type tomlOpts struct {
15         name      string
16         comment   string
17         commented bool
18         include   bool
19         omitempty bool
20 }
21
22 type encOpts struct {
23         quoteMapKeys bool
24 }
25
26 var encOptsDefaults = encOpts{
27         quoteMapKeys: false,
28 }
29
30 var timeType = reflect.TypeOf(time.Time{})
31 var marshalerType = reflect.TypeOf(new(Marshaler)).Elem()
32
33 // Check if the given marshall type maps to a Tree primitive
34 func isPrimitive(mtype reflect.Type) bool {
35         switch mtype.Kind() {
36         case reflect.Ptr:
37                 return isPrimitive(mtype.Elem())
38         case reflect.Bool:
39                 return true
40         case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
41                 return true
42         case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
43                 return true
44         case reflect.Float32, reflect.Float64:
45                 return true
46         case reflect.String:
47                 return true
48         case reflect.Struct:
49                 return mtype == timeType || isCustomMarshaler(mtype)
50         default:
51                 return false
52         }
53 }
54
55 // Check if the given marshall type maps to a Tree slice
56 func isTreeSlice(mtype reflect.Type) bool {
57         switch mtype.Kind() {
58         case reflect.Slice:
59                 return !isOtherSlice(mtype)
60         default:
61                 return false
62         }
63 }
64
65 // Check if the given marshall type maps to a non-Tree slice
66 func isOtherSlice(mtype reflect.Type) bool {
67         switch mtype.Kind() {
68         case reflect.Ptr:
69                 return isOtherSlice(mtype.Elem())
70         case reflect.Slice:
71                 return isPrimitive(mtype.Elem()) || isOtherSlice(mtype.Elem())
72         default:
73                 return false
74         }
75 }
76
77 // Check if the given marshall type maps to a Tree
78 func isTree(mtype reflect.Type) bool {
79         switch mtype.Kind() {
80         case reflect.Map:
81                 return true
82         case reflect.Struct:
83                 return !isPrimitive(mtype)
84         default:
85                 return false
86         }
87 }
88
89 func isCustomMarshaler(mtype reflect.Type) bool {
90         return mtype.Implements(marshalerType)
91 }
92
93 func callCustomMarshaler(mval reflect.Value) ([]byte, error) {
94         return mval.Interface().(Marshaler).MarshalTOML()
95 }
96
97 // Marshaler is the interface implemented by types that
98 // can marshal themselves into valid TOML.
99 type Marshaler interface {
100         MarshalTOML() ([]byte, error)
101 }
102
103 /*
104 Marshal returns the TOML encoding of v.  Behavior is similar to the Go json
105 encoder, except that there is no concept of a Marshaler interface or MarshalTOML
106 function for sub-structs, and currently only definite types can be marshaled
107 (i.e. no `interface{}`).
108
109 The following struct annotations are supported:
110
111   toml:"Field"      Overrides the field's name to output.
112   omitempty         When set, empty values and groups are not emitted.
113   comment:"comment" Emits a # comment on the same line. This supports new lines.
114   commented:"true"  Emits the value as commented.
115
116 Note that pointers are automatically assigned the "omitempty" option, as TOML
117 explicitly does not handle null values (saying instead the label should be
118 dropped).
119
120 Tree structural types and corresponding marshal types:
121
122   *Tree                            (*)struct, (*)map[string]interface{}
123   []*Tree                          (*)[](*)struct, (*)[](*)map[string]interface{}
124   []interface{} (as interface{})   (*)[]primitive, (*)[]([]interface{})
125   interface{}                      (*)primitive
126
127 Tree primitive types and corresponding marshal types:
128
129   uint64     uint, uint8-uint64, pointers to same
130   int64      int, int8-uint64, pointers to same
131   float64    float32, float64, pointers to same
132   string     string, pointers to same
133   bool       bool, pointers to same
134   time.Time  time.Time{}, pointers to same
135 */
136 func Marshal(v interface{}) ([]byte, error) {
137         return NewEncoder(nil).marshal(v)
138 }
139
140 // Encoder writes TOML values to an output stream.
141 type Encoder struct {
142         w io.Writer
143         encOpts
144 }
145
146 // NewEncoder returns a new encoder that writes to w.
147 func NewEncoder(w io.Writer) *Encoder {
148         return &Encoder{
149                 w:       w,
150                 encOpts: encOptsDefaults,
151         }
152 }
153
154 // Encode writes the TOML encoding of v to the stream.
155 //
156 // See the documentation for Marshal for details.
157 func (e *Encoder) Encode(v interface{}) error {
158         b, err := e.marshal(v)
159         if err != nil {
160                 return err
161         }
162         if _, err := e.w.Write(b); err != nil {
163                 return err
164         }
165         return nil
166 }
167
168 // QuoteMapKeys sets up the encoder to encode
169 // maps with string type keys with quoted TOML keys.
170 //
171 // This relieves the character limitations on map keys.
172 func (e *Encoder) QuoteMapKeys(v bool) *Encoder {
173         e.quoteMapKeys = v
174         return e
175 }
176
177 func (e *Encoder) marshal(v interface{}) ([]byte, error) {
178         mtype := reflect.TypeOf(v)
179         if mtype.Kind() != reflect.Struct {
180                 return []byte{}, errors.New("Only a struct can be marshaled to TOML")
181         }
182         sval := reflect.ValueOf(v)
183         if isCustomMarshaler(mtype) {
184                 return callCustomMarshaler(sval)
185         }
186         t, err := e.valueToTree(mtype, sval)
187         if err != nil {
188                 return []byte{}, err
189         }
190         s, err := t.ToTomlString()
191         return []byte(s), err
192 }
193
194 // Convert given marshal struct or map value to toml tree
195 func (e *Encoder) valueToTree(mtype reflect.Type, mval reflect.Value) (*Tree, error) {
196         if mtype.Kind() == reflect.Ptr {
197                 return e.valueToTree(mtype.Elem(), mval.Elem())
198         }
199         tval := newTree()
200         switch mtype.Kind() {
201         case reflect.Struct:
202                 for i := 0; i < mtype.NumField(); i++ {
203                         mtypef, mvalf := mtype.Field(i), mval.Field(i)
204                         opts := tomlOptions(mtypef)
205                         if opts.include && (!opts.omitempty || !isZero(mvalf)) {
206                                 val, err := e.valueToToml(mtypef.Type, mvalf)
207                                 if err != nil {
208                                         return nil, err
209                                 }
210                                 tval.Set(opts.name, opts.comment, opts.commented, val)
211                         }
212                 }
213         case reflect.Map:
214                 for _, key := range mval.MapKeys() {
215                         mvalf := mval.MapIndex(key)
216                         val, err := e.valueToToml(mtype.Elem(), mvalf)
217                         if err != nil {
218                                 return nil, err
219                         }
220                         if e.quoteMapKeys {
221                                 keyStr, err := tomlValueStringRepresentation(key.String())
222                                 if err != nil {
223                                         return nil, err
224                                 }
225                                 tval.SetPath([]string{keyStr}, "", false, val)
226                         } else {
227                                 tval.Set(key.String(), "", false, val)
228                         }
229                 }
230         }
231         return tval, nil
232 }
233
234 // Convert given marshal slice to slice of Toml trees
235 func (e *Encoder) valueToTreeSlice(mtype reflect.Type, mval reflect.Value) ([]*Tree, error) {
236         tval := make([]*Tree, mval.Len(), mval.Len())
237         for i := 0; i < mval.Len(); i++ {
238                 val, err := e.valueToTree(mtype.Elem(), mval.Index(i))
239                 if err != nil {
240                         return nil, err
241                 }
242                 tval[i] = val
243         }
244         return tval, nil
245 }
246
247 // Convert given marshal slice to slice of toml values
248 func (e *Encoder) valueToOtherSlice(mtype reflect.Type, mval reflect.Value) (interface{}, error) {
249         tval := make([]interface{}, mval.Len(), mval.Len())
250         for i := 0; i < mval.Len(); i++ {
251                 val, err := e.valueToToml(mtype.Elem(), mval.Index(i))
252                 if err != nil {
253                         return nil, err
254                 }
255                 tval[i] = val
256         }
257         return tval, nil
258 }
259
260 // Convert given marshal value to toml value
261 func (e *Encoder) valueToToml(mtype reflect.Type, mval reflect.Value) (interface{}, error) {
262         if mtype.Kind() == reflect.Ptr {
263                 return e.valueToToml(mtype.Elem(), mval.Elem())
264         }
265         switch {
266         case isCustomMarshaler(mtype):
267                 return callCustomMarshaler(mval)
268         case isTree(mtype):
269                 return e.valueToTree(mtype, mval)
270         case isTreeSlice(mtype):
271                 return e.valueToTreeSlice(mtype, mval)
272         case isOtherSlice(mtype):
273                 return e.valueToOtherSlice(mtype, mval)
274         default:
275                 switch mtype.Kind() {
276                 case reflect.Bool:
277                         return mval.Bool(), nil
278                 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
279                         return mval.Int(), nil
280                 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
281                         return mval.Uint(), nil
282                 case reflect.Float32, reflect.Float64:
283                         return mval.Float(), nil
284                 case reflect.String:
285                         return mval.String(), nil
286                 case reflect.Struct:
287                         return mval.Interface().(time.Time), nil
288                 default:
289                         return nil, fmt.Errorf("Marshal can't handle %v(%v)", mtype, mtype.Kind())
290                 }
291         }
292 }
293
294 // Unmarshal attempts to unmarshal the Tree into a Go struct pointed by v.
295 // Neither Unmarshaler interfaces nor UnmarshalTOML functions are supported for
296 // sub-structs, and only definite types can be unmarshaled.
297 func (t *Tree) Unmarshal(v interface{}) error {
298         d := Decoder{tval: t}
299         return d.unmarshal(v)
300 }
301
302 // Marshal returns the TOML encoding of Tree.
303 // See Marshal() documentation for types mapping table.
304 func (t *Tree) Marshal() ([]byte, error) {
305         var buf bytes.Buffer
306         err := NewEncoder(&buf).Encode(t)
307         return buf.Bytes(), err
308 }
309
310 // Unmarshal parses the TOML-encoded data and stores the result in the value
311 // pointed to by v. Behavior is similar to the Go json encoder, except that there
312 // is no concept of an Unmarshaler interface or UnmarshalTOML function for
313 // sub-structs, and currently only definite types can be unmarshaled to (i.e. no
314 // `interface{}`).
315 //
316 // The following struct annotations are supported:
317 //
318 //   toml:"Field" Overrides the field's name to map to.
319 //
320 // See Marshal() documentation for types mapping table.
321 func Unmarshal(data []byte, v interface{}) error {
322         t, err := LoadReader(bytes.NewReader(data))
323         if err != nil {
324                 return err
325         }
326         return t.Unmarshal(v)
327 }
328
329 // Decoder reads and decodes TOML values from an input stream.
330 type Decoder struct {
331         r    io.Reader
332         tval *Tree
333         encOpts
334 }
335
336 // NewDecoder returns a new decoder that reads from r.
337 func NewDecoder(r io.Reader) *Decoder {
338         return &Decoder{
339                 r:       r,
340                 encOpts: encOptsDefaults,
341         }
342 }
343
344 // Decode reads a TOML-encoded value from it's input
345 // and unmarshals it in the value pointed at by v.
346 //
347 // See the documentation for Marshal for details.
348 func (d *Decoder) Decode(v interface{}) error {
349         var err error
350         d.tval, err = LoadReader(d.r)
351         if err != nil {
352                 return err
353         }
354         return d.unmarshal(v)
355 }
356
357 func (d *Decoder) unmarshal(v interface{}) error {
358         mtype := reflect.TypeOf(v)
359         if mtype.Kind() != reflect.Ptr || mtype.Elem().Kind() != reflect.Struct {
360                 return errors.New("Only a pointer to struct can be unmarshaled from TOML")
361         }
362
363         sval, err := d.valueFromTree(mtype.Elem(), d.tval)
364         if err != nil {
365                 return err
366         }
367         reflect.ValueOf(v).Elem().Set(sval)
368         return nil
369 }
370
371 // Convert toml tree to marshal struct or map, using marshal type
372 func (d *Decoder) valueFromTree(mtype reflect.Type, tval *Tree) (reflect.Value, error) {
373         if mtype.Kind() == reflect.Ptr {
374                 return d.unwrapPointer(mtype, tval)
375         }
376         var mval reflect.Value
377         switch mtype.Kind() {
378         case reflect.Struct:
379                 mval = reflect.New(mtype).Elem()
380                 for i := 0; i < mtype.NumField(); i++ {
381                         mtypef := mtype.Field(i)
382                         opts := tomlOptions(mtypef)
383                         if opts.include {
384                                 baseKey := opts.name
385                                 keysToTry := []string{baseKey, strings.ToLower(baseKey), strings.ToTitle(baseKey)}
386                                 for _, key := range keysToTry {
387                                         exists := tval.Has(key)
388                                         if !exists {
389                                                 continue
390                                         }
391                                         val := tval.Get(key)
392                                         mvalf, err := d.valueFromToml(mtypef.Type, val)
393                                         if err != nil {
394                                                 return mval, formatError(err, tval.GetPosition(key))
395                                         }
396                                         mval.Field(i).Set(mvalf)
397                                         break
398                                 }
399                         }
400                 }
401         case reflect.Map:
402                 mval = reflect.MakeMap(mtype)
403                 for _, key := range tval.Keys() {
404                         // TODO: path splits key
405                         val := tval.GetPath([]string{key})
406                         mvalf, err := d.valueFromToml(mtype.Elem(), val)
407                         if err != nil {
408                                 return mval, formatError(err, tval.GetPosition(key))
409                         }
410                         mval.SetMapIndex(reflect.ValueOf(key), mvalf)
411                 }
412         }
413         return mval, nil
414 }
415
416 // Convert toml value to marshal struct/map slice, using marshal type
417 func (d *Decoder) valueFromTreeSlice(mtype reflect.Type, tval []*Tree) (reflect.Value, error) {
418         mval := reflect.MakeSlice(mtype, len(tval), len(tval))
419         for i := 0; i < len(tval); i++ {
420                 val, err := d.valueFromTree(mtype.Elem(), tval[i])
421                 if err != nil {
422                         return mval, err
423                 }
424                 mval.Index(i).Set(val)
425         }
426         return mval, nil
427 }
428
429 // Convert toml value to marshal primitive slice, using marshal type
430 func (d *Decoder) valueFromOtherSlice(mtype reflect.Type, tval []interface{}) (reflect.Value, error) {
431         mval := reflect.MakeSlice(mtype, len(tval), len(tval))
432         for i := 0; i < len(tval); i++ {
433                 val, err := d.valueFromToml(mtype.Elem(), tval[i])
434                 if err != nil {
435                         return mval, err
436                 }
437                 mval.Index(i).Set(val)
438         }
439         return mval, nil
440 }
441
442 // Convert toml value to marshal value, using marshal type
443 func (d *Decoder) valueFromToml(mtype reflect.Type, tval interface{}) (reflect.Value, error) {
444         if mtype.Kind() == reflect.Ptr {
445                 return d.unwrapPointer(mtype, tval)
446         }
447
448         switch tval.(type) {
449         case *Tree:
450                 if isTree(mtype) {
451                         return d.valueFromTree(mtype, tval.(*Tree))
452                 } else {
453                         return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to a tree", tval, tval)
454                 }
455         case []*Tree:
456                 if isTreeSlice(mtype) {
457                         return d.valueFromTreeSlice(mtype, tval.([]*Tree))
458                 } else {
459                         return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to trees", tval, tval)
460                 }
461         case []interface{}:
462                 if isOtherSlice(mtype) {
463                         return d.valueFromOtherSlice(mtype, tval.([]interface{}))
464                 } else {
465                         return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to a slice", tval, tval)
466                 }
467         default:
468                 switch mtype.Kind() {
469                 case reflect.Bool:
470                         val, ok := tval.(bool)
471                         if !ok {
472                                 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to bool", tval, tval)
473                         }
474                         return reflect.ValueOf(val), nil
475                 case reflect.Int:
476                         val, ok := tval.(int64)
477                         if !ok {
478                                 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval)
479                         }
480                         return reflect.ValueOf(int(val)), nil
481                 case reflect.Int8:
482                         val, ok := tval.(int64)
483                         if !ok {
484                                 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval)
485                         }
486                         return reflect.ValueOf(int8(val)), nil
487                 case reflect.Int16:
488                         val, ok := tval.(int64)
489                         if !ok {
490                                 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval)
491                         }
492                         return reflect.ValueOf(int16(val)), nil
493                 case reflect.Int32:
494                         val, ok := tval.(int64)
495                         if !ok {
496                                 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval)
497                         }
498                         return reflect.ValueOf(int32(val)), nil
499                 case reflect.Int64:
500                         val, ok := tval.(int64)
501                         if !ok {
502                                 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval)
503                         }
504                         return reflect.ValueOf(val), nil
505                 case reflect.Uint:
506                         val, ok := tval.(int64)
507                         if !ok {
508                                 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval)
509                         }
510                         return reflect.ValueOf(uint(val)), nil
511                 case reflect.Uint8:
512                         val, ok := tval.(int64)
513                         if !ok {
514                                 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval)
515                         }
516                         return reflect.ValueOf(uint8(val)), nil
517                 case reflect.Uint16:
518                         val, ok := tval.(int64)
519                         if !ok {
520                                 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval)
521                         }
522                         return reflect.ValueOf(uint16(val)), nil
523                 case reflect.Uint32:
524                         val, ok := tval.(int64)
525                         if !ok {
526                                 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval)
527                         }
528                         return reflect.ValueOf(uint32(val)), nil
529                 case reflect.Uint64:
530                         val, ok := tval.(int64)
531                         if !ok {
532                                 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval)
533                         }
534                         return reflect.ValueOf(uint64(val)), nil
535                 case reflect.Float32:
536                         val, ok := tval.(float64)
537                         if !ok {
538                                 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to float", tval, tval)
539                         }
540                         return reflect.ValueOf(float32(val)), nil
541                 case reflect.Float64:
542                         val, ok := tval.(float64)
543                         if !ok {
544                                 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to float", tval, tval)
545                         }
546                         return reflect.ValueOf(val), nil
547                 case reflect.String:
548                         val, ok := tval.(string)
549                         if !ok {
550                                 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to string", tval, tval)
551                         }
552                         return reflect.ValueOf(val), nil
553                 case reflect.Struct:
554                         val, ok := tval.(time.Time)
555                         if !ok {
556                                 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to time", tval, tval)
557                         }
558                         return reflect.ValueOf(val), nil
559                 default:
560                         return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v(%v)", tval, tval, mtype, mtype.Kind())
561                 }
562         }
563 }
564
565 func (d *Decoder) unwrapPointer(mtype reflect.Type, tval interface{}) (reflect.Value, error) {
566         val, err := d.valueFromToml(mtype.Elem(), tval)
567         if err != nil {
568                 return reflect.ValueOf(nil), err
569         }
570         mval := reflect.New(mtype.Elem())
571         mval.Elem().Set(val)
572         return mval, nil
573 }
574
575 func tomlOptions(vf reflect.StructField) tomlOpts {
576         tag := vf.Tag.Get("toml")
577         parse := strings.Split(tag, ",")
578         var comment string
579         if c := vf.Tag.Get("comment"); c != "" {
580                 comment = c
581         }
582         commented, _ := strconv.ParseBool(vf.Tag.Get("commented"))
583         result := tomlOpts{name: vf.Name, comment: comment, commented: commented, include: true, omitempty: false}
584         if parse[0] != "" {
585                 if parse[0] == "-" && len(parse) == 1 {
586                         result.include = false
587                 } else {
588                         result.name = strings.Trim(parse[0], " ")
589                 }
590         }
591         if vf.PkgPath != "" {
592                 result.include = false
593         }
594         if len(parse) > 1 && strings.Trim(parse[1], " ") == "omitempty" {
595                 result.omitempty = true
596         }
597         if vf.Type.Kind() == reflect.Ptr {
598                 result.omitempty = true
599         }
600         return result
601 }
602
603 func isZero(val reflect.Value) bool {
604         switch val.Type().Kind() {
605         case reflect.Map:
606                 fallthrough
607         case reflect.Array:
608                 fallthrough
609         case reflect.Slice:
610                 return val.Len() == 0
611         default:
612                 return reflect.DeepEqual(val.Interface(), reflect.Zero(val.Type()).Interface())
613         }
614 }
615
616 func formatError(err error, pos Position) error {
617         if err.Error()[0] == '(' { // Error already contains position information
618                 return err
619         }
620         return fmt.Errorf("%s: %s", pos, err)
621 }