gopkg.in/alecthomas/gometalinter.v3@v3.0.0/_linters/src/github.com/BurntSushi/toml/decode.go (about)

     1  package toml
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"io/ioutil"
     7  	"math"
     8  	"reflect"
     9  	"strings"
    10  	"time"
    11  )
    12  
    13  func e(format string, args ...interface{}) error {
    14  	return fmt.Errorf("toml: "+format, args...)
    15  }
    16  
    17  // Unmarshaler is the interface implemented by objects that can unmarshal a
    18  // TOML description of themselves.
    19  type Unmarshaler interface {
    20  	UnmarshalTOML(interface{}) error
    21  }
    22  
    23  // Unmarshal decodes the contents of `p` in TOML format into a pointer `v`.
    24  func Unmarshal(p []byte, v interface{}) error {
    25  	_, err := Decode(string(p), v)
    26  	return err
    27  }
    28  
    29  // Primitive is a TOML value that hasn't been decoded into a Go value.
    30  // When using the various `Decode*` functions, the type `Primitive` may
    31  // be given to any value, and its decoding will be delayed.
    32  //
    33  // A `Primitive` value can be decoded using the `PrimitiveDecode` function.
    34  //
    35  // The underlying representation of a `Primitive` value is subject to change.
    36  // Do not rely on it.
    37  //
    38  // N.B. Primitive values are still parsed, so using them will only avoid
    39  // the overhead of reflection. They can be useful when you don't know the
    40  // exact type of TOML data until run time.
    41  type Primitive struct {
    42  	undecoded interface{}
    43  	context   Key
    44  }
    45  
    46  // DEPRECATED!
    47  //
    48  // Use MetaData.PrimitiveDecode instead.
    49  func PrimitiveDecode(primValue Primitive, v interface{}) error {
    50  	md := MetaData{decoded: make(map[string]bool)}
    51  	return md.unify(primValue.undecoded, rvalue(v))
    52  }
    53  
    54  // PrimitiveDecode is just like the other `Decode*` functions, except it
    55  // decodes a TOML value that has already been parsed. Valid primitive values
    56  // can *only* be obtained from values filled by the decoder functions,
    57  // including this method. (i.e., `v` may contain more `Primitive`
    58  // values.)
    59  //
    60  // Meta data for primitive values is included in the meta data returned by
    61  // the `Decode*` functions with one exception: keys returned by the Undecoded
    62  // method will only reflect keys that were decoded. Namely, any keys hidden
    63  // behind a Primitive will be considered undecoded. Executing this method will
    64  // update the undecoded keys in the meta data. (See the example.)
    65  func (md *MetaData) PrimitiveDecode(primValue Primitive, v interface{}) error {
    66  	md.context = primValue.context
    67  	defer func() { md.context = nil }()
    68  	return md.unify(primValue.undecoded, rvalue(v))
    69  }
    70  
    71  // Decode will decode the contents of `data` in TOML format into a pointer
    72  // `v`.
    73  //
    74  // TOML hashes correspond to Go structs or maps. (Dealer's choice. They can be
    75  // used interchangeably.)
    76  //
    77  // TOML arrays of tables correspond to either a slice of structs or a slice
    78  // of maps.
    79  //
    80  // TOML datetimes correspond to Go `time.Time` values.
    81  //
    82  // All other TOML types (float, string, int, bool and array) correspond
    83  // to the obvious Go types.
    84  //
    85  // An exception to the above rules is if a type implements the
    86  // encoding.TextUnmarshaler interface. In this case, any primitive TOML value
    87  // (floats, strings, integers, booleans and datetimes) will be converted to
    88  // a byte string and given to the value's UnmarshalText method. See the
    89  // Unmarshaler example for a demonstration with time duration strings.
    90  //
    91  // Key mapping
    92  //
    93  // TOML keys can map to either keys in a Go map or field names in a Go
    94  // struct. The special `toml` struct tag may be used to map TOML keys to
    95  // struct fields that don't match the key name exactly. (See the example.)
    96  // A case insensitive match to struct names will be tried if an exact match
    97  // can't be found.
    98  //
    99  // The mapping between TOML values and Go values is loose. That is, there
   100  // may exist TOML values that cannot be placed into your representation, and
   101  // there may be parts of your representation that do not correspond to
   102  // TOML values. This loose mapping can be made stricter by using the IsDefined
   103  // and/or Undecoded methods on the MetaData returned.
   104  //
   105  // This decoder will not handle cyclic types. If a cyclic type is passed,
   106  // `Decode` will not terminate.
   107  func Decode(data string, v interface{}) (MetaData, error) {
   108  	rv := reflect.ValueOf(v)
   109  	if rv.Kind() != reflect.Ptr {
   110  		return MetaData{}, e("Decode of non-pointer %s", reflect.TypeOf(v))
   111  	}
   112  	if rv.IsNil() {
   113  		return MetaData{}, e("Decode of nil %s", reflect.TypeOf(v))
   114  	}
   115  	p, err := parse(data)
   116  	if err != nil {
   117  		return MetaData{}, err
   118  	}
   119  	md := MetaData{
   120  		p.mapping, p.types, p.ordered,
   121  		make(map[string]bool, len(p.ordered)), nil,
   122  	}
   123  	return md, md.unify(p.mapping, indirect(rv))
   124  }
   125  
   126  // DecodeFile is just like Decode, except it will automatically read the
   127  // contents of the file at `fpath` and decode it for you.
   128  func DecodeFile(fpath string, v interface{}) (MetaData, error) {
   129  	bs, err := ioutil.ReadFile(fpath)
   130  	if err != nil {
   131  		return MetaData{}, err
   132  	}
   133  	return Decode(string(bs), v)
   134  }
   135  
   136  // DecodeReader is just like Decode, except it will consume all bytes
   137  // from the reader and decode it for you.
   138  func DecodeReader(r io.Reader, v interface{}) (MetaData, error) {
   139  	bs, err := ioutil.ReadAll(r)
   140  	if err != nil {
   141  		return MetaData{}, err
   142  	}
   143  	return Decode(string(bs), v)
   144  }
   145  
   146  // unify performs a sort of type unification based on the structure of `rv`,
   147  // which is the client representation.
   148  //
   149  // Any type mismatch produces an error. Finding a type that we don't know
   150  // how to handle produces an unsupported type error.
   151  func (md *MetaData) unify(data interface{}, rv reflect.Value) error {
   152  
   153  	// Special case. Look for a `Primitive` value.
   154  	if rv.Type() == reflect.TypeOf((*Primitive)(nil)).Elem() {
   155  		// Save the undecoded data and the key context into the primitive
   156  		// value.
   157  		context := make(Key, len(md.context))
   158  		copy(context, md.context)
   159  		rv.Set(reflect.ValueOf(Primitive{
   160  			undecoded: data,
   161  			context:   context,
   162  		}))
   163  		return nil
   164  	}
   165  
   166  	// Special case. Unmarshaler Interface support.
   167  	if rv.CanAddr() {
   168  		if v, ok := rv.Addr().Interface().(Unmarshaler); ok {
   169  			return v.UnmarshalTOML(data)
   170  		}
   171  	}
   172  
   173  	// Special case. Handle time.Time values specifically.
   174  	// TODO: Remove this code when we decide to drop support for Go 1.1.
   175  	// This isn't necessary in Go 1.2 because time.Time satisfies the encoding
   176  	// interfaces.
   177  	if rv.Type().AssignableTo(rvalue(time.Time{}).Type()) {
   178  		return md.unifyDatetime(data, rv)
   179  	}
   180  
   181  	// Special case. Look for a value satisfying the TextUnmarshaler interface.
   182  	if v, ok := rv.Interface().(TextUnmarshaler); ok {
   183  		return md.unifyText(data, v)
   184  	}
   185  	// BUG(burntsushi)
   186  	// The behavior here is incorrect whenever a Go type satisfies the
   187  	// encoding.TextUnmarshaler interface but also corresponds to a TOML
   188  	// hash or array. In particular, the unmarshaler should only be applied
   189  	// to primitive TOML values. But at this point, it will be applied to
   190  	// all kinds of values and produce an incorrect error whenever those values
   191  	// are hashes or arrays (including arrays of tables).
   192  
   193  	k := rv.Kind()
   194  
   195  	// laziness
   196  	if k >= reflect.Int && k <= reflect.Uint64 {
   197  		return md.unifyInt(data, rv)
   198  	}
   199  	switch k {
   200  	case reflect.Ptr:
   201  		elem := reflect.New(rv.Type().Elem())
   202  		err := md.unify(data, reflect.Indirect(elem))
   203  		if err != nil {
   204  			return err
   205  		}
   206  		rv.Set(elem)
   207  		return nil
   208  	case reflect.Struct:
   209  		return md.unifyStruct(data, rv)
   210  	case reflect.Map:
   211  		return md.unifyMap(data, rv)
   212  	case reflect.Array:
   213  		return md.unifyArray(data, rv)
   214  	case reflect.Slice:
   215  		return md.unifySlice(data, rv)
   216  	case reflect.String:
   217  		return md.unifyString(data, rv)
   218  	case reflect.Bool:
   219  		return md.unifyBool(data, rv)
   220  	case reflect.Interface:
   221  		// we only support empty interfaces.
   222  		if rv.NumMethod() > 0 {
   223  			return e("unsupported type %s", rv.Type())
   224  		}
   225  		return md.unifyAnything(data, rv)
   226  	case reflect.Float32:
   227  		fallthrough
   228  	case reflect.Float64:
   229  		return md.unifyFloat64(data, rv)
   230  	}
   231  	return e("unsupported type %s", rv.Kind())
   232  }
   233  
   234  func (md *MetaData) unifyStruct(mapping interface{}, rv reflect.Value) error {
   235  	tmap, ok := mapping.(map[string]interface{})
   236  	if !ok {
   237  		if mapping == nil {
   238  			return nil
   239  		}
   240  		return e("type mismatch for %s: expected table but found %T",
   241  			rv.Type().String(), mapping)
   242  	}
   243  
   244  	for key, datum := range tmap {
   245  		var f *field
   246  		fields := cachedTypeFields(rv.Type())
   247  		for i := range fields {
   248  			ff := &fields[i]
   249  			if ff.name == key {
   250  				f = ff
   251  				break
   252  			}
   253  			if f == nil && strings.EqualFold(ff.name, key) {
   254  				f = ff
   255  			}
   256  		}
   257  		if f != nil {
   258  			subv := rv
   259  			for _, i := range f.index {
   260  				subv = indirect(subv.Field(i))
   261  			}
   262  			if isUnifiable(subv) {
   263  				md.decoded[md.context.add(key).String()] = true
   264  				md.context = append(md.context, key)
   265  				if err := md.unify(datum, subv); err != nil {
   266  					return err
   267  				}
   268  				md.context = md.context[0 : len(md.context)-1]
   269  			} else if f.name != "" {
   270  				// Bad user! No soup for you!
   271  				return e("cannot write unexported field %s.%s",
   272  					rv.Type().String(), f.name)
   273  			}
   274  		}
   275  	}
   276  	return nil
   277  }
   278  
   279  func (md *MetaData) unifyMap(mapping interface{}, rv reflect.Value) error {
   280  	tmap, ok := mapping.(map[string]interface{})
   281  	if !ok {
   282  		if tmap == nil {
   283  			return nil
   284  		}
   285  		return badtype("map", mapping)
   286  	}
   287  	if rv.IsNil() {
   288  		rv.Set(reflect.MakeMap(rv.Type()))
   289  	}
   290  	for k, v := range tmap {
   291  		md.decoded[md.context.add(k).String()] = true
   292  		md.context = append(md.context, k)
   293  
   294  		rvkey := indirect(reflect.New(rv.Type().Key()))
   295  		rvval := reflect.Indirect(reflect.New(rv.Type().Elem()))
   296  		if err := md.unify(v, rvval); err != nil {
   297  			return err
   298  		}
   299  		md.context = md.context[0 : len(md.context)-1]
   300  
   301  		rvkey.SetString(k)
   302  		rv.SetMapIndex(rvkey, rvval)
   303  	}
   304  	return nil
   305  }
   306  
   307  func (md *MetaData) unifyArray(data interface{}, rv reflect.Value) error {
   308  	datav := reflect.ValueOf(data)
   309  	if datav.Kind() != reflect.Slice {
   310  		if !datav.IsValid() {
   311  			return nil
   312  		}
   313  		return badtype("slice", data)
   314  	}
   315  	sliceLen := datav.Len()
   316  	if sliceLen != rv.Len() {
   317  		return e("expected array length %d; got TOML array of length %d",
   318  			rv.Len(), sliceLen)
   319  	}
   320  	return md.unifySliceArray(datav, rv)
   321  }
   322  
   323  func (md *MetaData) unifySlice(data interface{}, rv reflect.Value) error {
   324  	datav := reflect.ValueOf(data)
   325  	if datav.Kind() != reflect.Slice {
   326  		if !datav.IsValid() {
   327  			return nil
   328  		}
   329  		return badtype("slice", data)
   330  	}
   331  	n := datav.Len()
   332  	if rv.IsNil() || rv.Cap() < n {
   333  		rv.Set(reflect.MakeSlice(rv.Type(), n, n))
   334  	}
   335  	rv.SetLen(n)
   336  	return md.unifySliceArray(datav, rv)
   337  }
   338  
   339  func (md *MetaData) unifySliceArray(data, rv reflect.Value) error {
   340  	sliceLen := data.Len()
   341  	for i := 0; i < sliceLen; i++ {
   342  		v := data.Index(i).Interface()
   343  		sliceval := indirect(rv.Index(i))
   344  		if err := md.unify(v, sliceval); err != nil {
   345  			return err
   346  		}
   347  	}
   348  	return nil
   349  }
   350  
   351  func (md *MetaData) unifyDatetime(data interface{}, rv reflect.Value) error {
   352  	if _, ok := data.(time.Time); ok {
   353  		rv.Set(reflect.ValueOf(data))
   354  		return nil
   355  	}
   356  	return badtype("time.Time", data)
   357  }
   358  
   359  func (md *MetaData) unifyString(data interface{}, rv reflect.Value) error {
   360  	if s, ok := data.(string); ok {
   361  		rv.SetString(s)
   362  		return nil
   363  	}
   364  	return badtype("string", data)
   365  }
   366  
   367  func (md *MetaData) unifyFloat64(data interface{}, rv reflect.Value) error {
   368  	if num, ok := data.(float64); ok {
   369  		switch rv.Kind() {
   370  		case reflect.Float32:
   371  			fallthrough
   372  		case reflect.Float64:
   373  			rv.SetFloat(num)
   374  		default:
   375  			panic("bug")
   376  		}
   377  		return nil
   378  	}
   379  	return badtype("float", data)
   380  }
   381  
   382  func (md *MetaData) unifyInt(data interface{}, rv reflect.Value) error {
   383  	if num, ok := data.(int64); ok {
   384  		if rv.Kind() >= reflect.Int && rv.Kind() <= reflect.Int64 {
   385  			switch rv.Kind() {
   386  			case reflect.Int, reflect.Int64:
   387  				// No bounds checking necessary.
   388  			case reflect.Int8:
   389  				if num < math.MinInt8 || num > math.MaxInt8 {
   390  					return e("value %d is out of range for int8", num)
   391  				}
   392  			case reflect.Int16:
   393  				if num < math.MinInt16 || num > math.MaxInt16 {
   394  					return e("value %d is out of range for int16", num)
   395  				}
   396  			case reflect.Int32:
   397  				if num < math.MinInt32 || num > math.MaxInt32 {
   398  					return e("value %d is out of range for int32", num)
   399  				}
   400  			}
   401  			rv.SetInt(num)
   402  		} else if rv.Kind() >= reflect.Uint && rv.Kind() <= reflect.Uint64 {
   403  			unum := uint64(num)
   404  			switch rv.Kind() {
   405  			case reflect.Uint, reflect.Uint64:
   406  				// No bounds checking necessary.
   407  			case reflect.Uint8:
   408  				if num < 0 || unum > math.MaxUint8 {
   409  					return e("value %d is out of range for uint8", num)
   410  				}
   411  			case reflect.Uint16:
   412  				if num < 0 || unum > math.MaxUint16 {
   413  					return e("value %d is out of range for uint16", num)
   414  				}
   415  			case reflect.Uint32:
   416  				if num < 0 || unum > math.MaxUint32 {
   417  					return e("value %d is out of range for uint32", num)
   418  				}
   419  			}
   420  			rv.SetUint(unum)
   421  		} else {
   422  			panic("unreachable")
   423  		}
   424  		return nil
   425  	}
   426  	return badtype("integer", data)
   427  }
   428  
   429  func (md *MetaData) unifyBool(data interface{}, rv reflect.Value) error {
   430  	if b, ok := data.(bool); ok {
   431  		rv.SetBool(b)
   432  		return nil
   433  	}
   434  	return badtype("boolean", data)
   435  }
   436  
   437  func (md *MetaData) unifyAnything(data interface{}, rv reflect.Value) error {
   438  	rv.Set(reflect.ValueOf(data))
   439  	return nil
   440  }
   441  
   442  func (md *MetaData) unifyText(data interface{}, v TextUnmarshaler) error {
   443  	var s string
   444  	switch sdata := data.(type) {
   445  	case TextMarshaler:
   446  		text, err := sdata.MarshalText()
   447  		if err != nil {
   448  			return err
   449  		}
   450  		s = string(text)
   451  	case fmt.Stringer:
   452  		s = sdata.String()
   453  	case string:
   454  		s = sdata
   455  	case bool:
   456  		s = fmt.Sprintf("%v", sdata)
   457  	case int64:
   458  		s = fmt.Sprintf("%d", sdata)
   459  	case float64:
   460  		s = fmt.Sprintf("%f", sdata)
   461  	default:
   462  		return badtype("primitive (string-like)", data)
   463  	}
   464  	if err := v.UnmarshalText([]byte(s)); err != nil {
   465  		return err
   466  	}
   467  	return nil
   468  }
   469  
   470  // rvalue returns a reflect.Value of `v`. All pointers are resolved.
   471  func rvalue(v interface{}) reflect.Value {
   472  	return indirect(reflect.ValueOf(v))
   473  }
   474  
   475  // indirect returns the value pointed to by a pointer.
   476  // Pointers are followed until the value is not a pointer.
   477  // New values are allocated for each nil pointer.
   478  //
   479  // An exception to this rule is if the value satisfies an interface of
   480  // interest to us (like encoding.TextUnmarshaler).
   481  func indirect(v reflect.Value) reflect.Value {
   482  	if v.Kind() != reflect.Ptr {
   483  		if v.CanSet() {
   484  			pv := v.Addr()
   485  			if _, ok := pv.Interface().(TextUnmarshaler); ok {
   486  				return pv
   487  			}
   488  		}
   489  		return v
   490  	}
   491  	if v.IsNil() {
   492  		v.Set(reflect.New(v.Type().Elem()))
   493  	}
   494  	return indirect(reflect.Indirect(v))
   495  }
   496  
   497  func isUnifiable(rv reflect.Value) bool {
   498  	if rv.CanSet() {
   499  		return true
   500  	}
   501  	if _, ok := rv.Interface().(TextUnmarshaler); ok {
   502  		return true
   503  	}
   504  	return false
   505  }
   506  
   507  func badtype(expected string, data interface{}) error {
   508  	return e("cannot load TOML value of type %T into a Go %s", data, expected)
   509  }