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