1package toml
2
3import (
4	"fmt"
5	"io"
6	"io/ioutil"
7	"math"
8	"reflect"
9	"strings"
10	"time"
11)
12
13func 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.
19type Unmarshaler interface {
20	UnmarshalTOML(interface{}) error
21}
22
23// Unmarshal decodes the contents of `p` in TOML format into a pointer `v`.
24func 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.
41type Primitive struct {
42	undecoded interface{}
43	context   Key
44}
45
46// DEPRECATED!
47//
48// Use MetaData.PrimitiveDecode instead.
49func 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.)
65func (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.
107func 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.
128func 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.
138func 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.
151func (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
234func (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
279func (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
307func (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
323func (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
339func (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
351func (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
359func (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
367func (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
382func (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
429func (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
437func (md *MetaData) unifyAnything(data interface{}, rv reflect.Value) error {
438	rv.Set(reflect.ValueOf(data))
439	return nil
440}
441
442func (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.
471func 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).
481func 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
497func 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
507func badtype(expected string, data interface{}) error {
508	return e("cannot load TOML value of type %T into a Go %s", data, expected)
509}
510