Files
go-toml/unmarshaler.go
T
Johanan Idicula b9e3b9c370 refactor: Use typeMismatchError rather than raw string error (#826)
Uses the existing method to DRY up the error message generation, and decorates
with position index where needed. No behaviour is changed, but it allows for
further changes to make error messaging more specific.

Related to: pelletier/go-toml#806
2022-10-30 13:44:16 -04:00

1228 lines
29 KiB
Go

package toml
import (
"encoding"
"errors"
"fmt"
"io"
"io/ioutil"
"math"
"reflect"
"strings"
"sync/atomic"
"time"
"github.com/pelletier/go-toml/v2/internal/ast"
"github.com/pelletier/go-toml/v2/internal/danger"
"github.com/pelletier/go-toml/v2/internal/tracker"
)
// Unmarshal deserializes a TOML document into a Go value.
//
// It is a shortcut for Decoder.Decode() with the default options.
func Unmarshal(data []byte, v interface{}) error {
p := parser{}
p.Reset(data)
d := decoder{p: &p}
return d.FromParser(v)
}
// Decoder reads and decode a TOML document from an input stream.
type Decoder struct {
// input
r io.Reader
// global settings
strict bool
}
// NewDecoder creates a new Decoder that will read from r.
func NewDecoder(r io.Reader) *Decoder {
return &Decoder{r: r}
}
// DisallowUnknownFields causes the Decoder to return an error when the
// destination is a struct and the input contains a key that does not match a
// non-ignored field.
//
// In that case, the Decoder returns a StrictMissingError that can be used to
// retrieve the individual errors as well as generate a human readable
// description of the missing fields.
func (d *Decoder) DisallowUnknownFields() *Decoder {
d.strict = true
return d
}
// Decode the whole content of r into v.
//
// By default, values in the document that don't exist in the target Go value
// are ignored. See Decoder.DisallowUnknownFields() to change this behavior.
//
// When a TOML local date, time, or date-time is decoded into a time.Time, its
// value is represented in time.Local timezone. Otherwise the approriate Local*
// structure is used. For time values, precision up to the nanosecond is
// supported by truncating extra digits.
//
// Empty tables decoded in an interface{} create an empty initialized
// map[string]interface{}.
//
// Types implementing the encoding.TextUnmarshaler interface are decoded from a
// TOML string.
//
// When decoding a number, go-toml will return an error if the number is out of
// bounds for the target type (which includes negative numbers when decoding
// into an unsigned int).
//
// If an error occurs while decoding the content of the document, this function
// returns a toml.DecodeError, providing context about the issue. When using
// strict mode and a field is missing, a `toml.StrictMissingError` is
// returned. In any other case, this function returns a standard Go error.
//
// # Type mapping
//
// List of supported TOML types and their associated accepted Go types:
//
// String -> string
// Integer -> uint*, int*, depending on size
// Float -> float*, depending on size
// Boolean -> bool
// Offset Date-Time -> time.Time
// Local Date-time -> LocalDateTime, time.Time
// Local Date -> LocalDate, time.Time
// Local Time -> LocalTime, time.Time
// Array -> slice and array, depending on elements types
// Table -> map and struct
// Inline Table -> same as Table
// Array of Tables -> same as Array and Table
func (d *Decoder) Decode(v interface{}) error {
b, err := ioutil.ReadAll(d.r)
if err != nil {
return fmt.Errorf("toml: %w", err)
}
p := parser{}
p.Reset(b)
dec := decoder{
p: &p,
strict: strict{
Enabled: d.strict,
},
}
return dec.FromParser(v)
}
type decoder struct {
// Which parser instance in use for this decoding session.
p *parser
// Flag indicating that the current expression is stashed.
// If set to true, calling nextExpr will not actually pull a new expression
// but turn off the flag instead.
stashedExpr bool
// Skip expressions until a table is found. This is set to true when a
// table could not be created (missing field in map), so all KV expressions
// need to be skipped.
skipUntilTable bool
// Tracks position in Go arrays.
// This is used when decoding [[array tables]] into Go arrays. Given array
// tables are separate TOML expression, we need to keep track of where we
// are at in the Go array, as we can't just introspect its size.
arrayIndexes map[reflect.Value]int
// Tracks keys that have been seen, with which type.
seen tracker.SeenTracker
// Strict mode
strict strict
// Current context for the error.
errorContext *errorContext
}
type errorContext struct {
Struct reflect.Type
Field []int
}
func (d *decoder) typeMismatchError(toml string, target reflect.Type) error {
if d.errorContext != nil && d.errorContext.Struct != nil {
ctx := d.errorContext
f := ctx.Struct.FieldByIndex(ctx.Field)
return fmt.Errorf("toml: cannot decode TOML %s into struct field %s.%s of type %s", toml, ctx.Struct, f.Name, f.Type)
}
return fmt.Errorf("toml: cannot decode TOML %s into a Go value of type %s", toml, target)
}
func (d *decoder) expr() *ast.Node {
return d.p.Expression()
}
func (d *decoder) nextExpr() bool {
if d.stashedExpr {
d.stashedExpr = false
return true
}
return d.p.NextExpression()
}
func (d *decoder) stashExpr() {
d.stashedExpr = true
}
func (d *decoder) arrayIndex(shouldAppend bool, v reflect.Value) int {
if d.arrayIndexes == nil {
d.arrayIndexes = make(map[reflect.Value]int, 1)
}
idx, ok := d.arrayIndexes[v]
if !ok {
d.arrayIndexes[v] = 0
} else if shouldAppend {
idx++
d.arrayIndexes[v] = idx
}
return idx
}
func (d *decoder) FromParser(v interface{}) error {
r := reflect.ValueOf(v)
if r.Kind() != reflect.Ptr {
return fmt.Errorf("toml: decoding can only be performed into a pointer, not %s", r.Kind())
}
if r.IsNil() {
return fmt.Errorf("toml: decoding pointer target cannot be nil")
}
r = r.Elem()
if r.Kind() == reflect.Interface && r.IsNil() {
newMap := map[string]interface{}{}
r.Set(reflect.ValueOf(newMap))
}
err := d.fromParser(r)
if err == nil {
return d.strict.Error(d.p.data)
}
var e *decodeError
if errors.As(err, &e) {
return wrapDecodeError(d.p.data, e)
}
return err
}
func (d *decoder) fromParser(root reflect.Value) error {
for d.nextExpr() {
err := d.handleRootExpression(d.expr(), root)
if err != nil {
return err
}
}
return d.p.Error()
}
/*
Rules for the unmarshal code:
- The stack is used to keep track of which values need to be set where.
- handle* functions <=> switch on a given ast.Kind.
- unmarshalX* functions need to unmarshal a node of kind X.
- An "object" is either a struct or a map.
*/
func (d *decoder) handleRootExpression(expr *ast.Node, v reflect.Value) error {
var x reflect.Value
var err error
if !(d.skipUntilTable && expr.Kind == ast.KeyValue) {
err = d.seen.CheckExpression(expr)
if err != nil {
return err
}
}
switch expr.Kind {
case ast.KeyValue:
if d.skipUntilTable {
return nil
}
x, err = d.handleKeyValue(expr, v)
case ast.Table:
d.skipUntilTable = false
d.strict.EnterTable(expr)
x, err = d.handleTable(expr.Key(), v)
case ast.ArrayTable:
d.skipUntilTable = false
d.strict.EnterArrayTable(expr)
x, err = d.handleArrayTable(expr.Key(), v)
default:
panic(fmt.Errorf("parser should not permit expression of kind %s at document root", expr.Kind))
}
if d.skipUntilTable {
if expr.Kind == ast.Table || expr.Kind == ast.ArrayTable {
d.strict.MissingTable(expr)
}
} else if err == nil && x.IsValid() {
v.Set(x)
}
return err
}
func (d *decoder) handleArrayTable(key ast.Iterator, v reflect.Value) (reflect.Value, error) {
if key.Next() {
return d.handleArrayTablePart(key, v)
}
return d.handleKeyValues(v)
}
func (d *decoder) handleArrayTableCollectionLast(key ast.Iterator, v reflect.Value) (reflect.Value, error) {
switch v.Kind() {
case reflect.Interface:
elem := v.Elem()
if !elem.IsValid() {
elem = reflect.New(sliceInterfaceType).Elem()
elem.Set(reflect.MakeSlice(sliceInterfaceType, 0, 16))
} else if elem.Kind() == reflect.Slice {
if elem.Type() != sliceInterfaceType {
elem = reflect.New(sliceInterfaceType).Elem()
elem.Set(reflect.MakeSlice(sliceInterfaceType, 0, 16))
} else if !elem.CanSet() {
nelem := reflect.New(sliceInterfaceType).Elem()
nelem.Set(reflect.MakeSlice(sliceInterfaceType, elem.Len(), elem.Cap()))
reflect.Copy(nelem, elem)
elem = nelem
}
}
return d.handleArrayTableCollectionLast(key, elem)
case reflect.Ptr:
elem := v.Elem()
if !elem.IsValid() {
ptr := reflect.New(v.Type().Elem())
v.Set(ptr)
elem = ptr.Elem()
}
elem, err := d.handleArrayTableCollectionLast(key, elem)
if err != nil {
return reflect.Value{}, err
}
v.Elem().Set(elem)
return v, nil
case reflect.Slice:
elemType := v.Type().Elem()
var elem reflect.Value
if elemType.Kind() == reflect.Interface {
elem = makeMapStringInterface()
} else {
elem = reflect.New(elemType).Elem()
}
elem2, err := d.handleArrayTable(key, elem)
if err != nil {
return reflect.Value{}, err
}
if elem2.IsValid() {
elem = elem2
}
return reflect.Append(v, elem), nil
case reflect.Array:
idx := d.arrayIndex(true, v)
if idx >= v.Len() {
return v, fmt.Errorf("%s at position %d", d.typeMismatchError("array table", v.Type()), idx)
}
elem := v.Index(idx)
_, err := d.handleArrayTable(key, elem)
return v, err
default:
return reflect.Value{}, d.typeMismatchError("array table", v.Type())
}
}
// When parsing an array table expression, each part of the key needs to be
// evaluated like a normal key, but if it returns a collection, it also needs to
// point to the last element of the collection. Unless it is the last part of
// the key, then it needs to create a new element at the end.
func (d *decoder) handleArrayTableCollection(key ast.Iterator, v reflect.Value) (reflect.Value, error) {
if key.IsLast() {
return d.handleArrayTableCollectionLast(key, v)
}
switch v.Kind() {
case reflect.Ptr:
elem := v.Elem()
if !elem.IsValid() {
ptr := reflect.New(v.Type().Elem())
v.Set(ptr)
elem = ptr.Elem()
}
elem, err := d.handleArrayTableCollection(key, elem)
if err != nil {
return reflect.Value{}, err
}
if elem.IsValid() {
v.Elem().Set(elem)
}
return v, nil
case reflect.Slice:
elem := v.Index(v.Len() - 1)
x, err := d.handleArrayTable(key, elem)
if err != nil || d.skipUntilTable {
return reflect.Value{}, err
}
if x.IsValid() {
elem.Set(x)
}
return v, err
case reflect.Array:
idx := d.arrayIndex(false, v)
if idx >= v.Len() {
return v, fmt.Errorf("%s at position %d", d.typeMismatchError("array table", v.Type()), idx)
}
elem := v.Index(idx)
_, err := d.handleArrayTable(key, elem)
return v, err
}
return d.handleArrayTable(key, v)
}
func (d *decoder) handleKeyPart(key ast.Iterator, v reflect.Value, nextFn handlerFn, makeFn valueMakerFn) (reflect.Value, error) {
var rv reflect.Value
// First, dispatch over v to make sure it is a valid object.
// There is no guarantee over what it could be.
switch v.Kind() {
case reflect.Ptr:
elem := v.Elem()
if !elem.IsValid() {
v.Set(reflect.New(v.Type().Elem()))
}
elem = v.Elem()
return d.handleKeyPart(key, elem, nextFn, makeFn)
case reflect.Map:
vt := v.Type()
// Create the key for the map element. Convert to key type.
mk := reflect.ValueOf(string(key.Node().Data)).Convert(vt.Key())
// If the map does not exist, create it.
if v.IsNil() {
vt := v.Type()
v = reflect.MakeMap(vt)
rv = v
}
mv := v.MapIndex(mk)
set := false
if !mv.IsValid() {
// If there is no value in the map, create a new one according to
// the map type. If the element type is interface, create either a
// map[string]interface{} or a []interface{} depending on whether
// this is the last part of the array table key.
t := vt.Elem()
if t.Kind() == reflect.Interface {
mv = makeFn()
} else {
mv = reflect.New(t).Elem()
}
set = true
} else if mv.Kind() == reflect.Interface {
mv = mv.Elem()
if !mv.IsValid() {
mv = makeFn()
}
set = true
} else if !mv.CanAddr() {
vt := v.Type()
t := vt.Elem()
oldmv := mv
mv = reflect.New(t).Elem()
mv.Set(oldmv)
set = true
}
x, err := nextFn(key, mv)
if err != nil {
return reflect.Value{}, err
}
if x.IsValid() {
mv = x
set = true
}
if set {
v.SetMapIndex(mk, mv)
}
case reflect.Struct:
path, found := structFieldPath(v, string(key.Node().Data))
if !found {
d.skipUntilTable = true
return reflect.Value{}, nil
}
if d.errorContext == nil {
d.errorContext = new(errorContext)
}
t := v.Type()
d.errorContext.Struct = t
d.errorContext.Field = path
f := fieldByIndex(v, path)
x, err := nextFn(key, f)
if err != nil || d.skipUntilTable {
return reflect.Value{}, err
}
if x.IsValid() {
f.Set(x)
}
d.errorContext.Field = nil
d.errorContext.Struct = nil
case reflect.Interface:
if v.Elem().IsValid() {
v = v.Elem()
} else {
v = makeMapStringInterface()
}
x, err := d.handleKeyPart(key, v, nextFn, makeFn)
if err != nil {
return reflect.Value{}, err
}
if x.IsValid() {
v = x
}
rv = v
default:
panic(fmt.Errorf("unhandled part: %s", v.Kind()))
}
return rv, nil
}
// HandleArrayTablePart navigates the Go structure v using the key v. It is
// only used for the prefix (non-last) parts of an array-table. When
// encountering a collection, it should go to the last element.
func (d *decoder) handleArrayTablePart(key ast.Iterator, v reflect.Value) (reflect.Value, error) {
var makeFn valueMakerFn
if key.IsLast() {
makeFn = makeSliceInterface
} else {
makeFn = makeMapStringInterface
}
return d.handleKeyPart(key, v, d.handleArrayTableCollection, makeFn)
}
// HandleTable returns a reference when it has checked the next expression but
// cannot handle it.
func (d *decoder) handleTable(key ast.Iterator, v reflect.Value) (reflect.Value, error) {
if v.Kind() == reflect.Slice {
if v.Len() == 0 {
return reflect.Value{}, newDecodeError(key.Node().Data, "cannot store a table in a slice")
}
elem := v.Index(v.Len() - 1)
x, err := d.handleTable(key, elem)
if err != nil {
return reflect.Value{}, err
}
if x.IsValid() {
elem.Set(x)
}
return reflect.Value{}, nil
}
if key.Next() {
// Still scoping the key
return d.handleTablePart(key, v)
}
// Done scoping the key.
// Now handle all the key-value expressions in this table.
return d.handleKeyValues(v)
}
// Handle root expressions until the end of the document or the next
// non-key-value.
func (d *decoder) handleKeyValues(v reflect.Value) (reflect.Value, error) {
var rv reflect.Value
for d.nextExpr() {
expr := d.expr()
if expr.Kind != ast.KeyValue {
// Stash the expression so that fromParser can just loop and use
// the right handler.
// We could just recurse ourselves here, but at least this gives a
// chance to pop the stack a bit.
d.stashExpr()
break
}
err := d.seen.CheckExpression(expr)
if err != nil {
return reflect.Value{}, err
}
x, err := d.handleKeyValue(expr, v)
if err != nil {
return reflect.Value{}, err
}
if x.IsValid() {
v = x
rv = x
}
}
return rv, nil
}
type (
handlerFn func(key ast.Iterator, v reflect.Value) (reflect.Value, error)
valueMakerFn func() reflect.Value
)
func makeMapStringInterface() reflect.Value {
return reflect.MakeMap(mapStringInterfaceType)
}
func makeSliceInterface() reflect.Value {
return reflect.MakeSlice(sliceInterfaceType, 0, 16)
}
func (d *decoder) handleTablePart(key ast.Iterator, v reflect.Value) (reflect.Value, error) {
return d.handleKeyPart(key, v, d.handleTable, makeMapStringInterface)
}
func (d *decoder) tryTextUnmarshaler(node *ast.Node, v reflect.Value) (bool, error) {
// Special case for time, because we allow to unmarshal to it from
// different kind of AST nodes.
if v.Type() == timeType {
return false, nil
}
if v.CanAddr() && v.Addr().Type().Implements(textUnmarshalerType) {
err := v.Addr().Interface().(encoding.TextUnmarshaler).UnmarshalText(node.Data)
if err != nil {
return false, newDecodeError(d.p.Raw(node.Raw), "%w", err)
}
return true, nil
}
return false, nil
}
func (d *decoder) handleValue(value *ast.Node, v reflect.Value) error {
for v.Kind() == reflect.Ptr {
v = initAndDereferencePointer(v)
}
ok, err := d.tryTextUnmarshaler(value, v)
if ok || err != nil {
return err
}
switch value.Kind {
case ast.String:
return d.unmarshalString(value, v)
case ast.Integer:
return d.unmarshalInteger(value, v)
case ast.Float:
return d.unmarshalFloat(value, v)
case ast.Bool:
return d.unmarshalBool(value, v)
case ast.DateTime:
return d.unmarshalDateTime(value, v)
case ast.LocalDate:
return d.unmarshalLocalDate(value, v)
case ast.LocalTime:
return d.unmarshalLocalTime(value, v)
case ast.LocalDateTime:
return d.unmarshalLocalDateTime(value, v)
case ast.InlineTable:
return d.unmarshalInlineTable(value, v)
case ast.Array:
return d.unmarshalArray(value, v)
default:
panic(fmt.Errorf("handleValue not implemented for %s", value.Kind))
}
}
func (d *decoder) unmarshalArray(array *ast.Node, v reflect.Value) error {
switch v.Kind() {
case reflect.Slice:
if v.IsNil() {
v.Set(reflect.MakeSlice(v.Type(), 0, 16))
} else {
v.SetLen(0)
}
case reflect.Array:
// arrays are always initialized
case reflect.Interface:
elem := v.Elem()
if !elem.IsValid() {
elem = reflect.New(sliceInterfaceType).Elem()
elem.Set(reflect.MakeSlice(sliceInterfaceType, 0, 16))
} else if elem.Kind() == reflect.Slice {
if elem.Type() != sliceInterfaceType {
elem = reflect.New(sliceInterfaceType).Elem()
elem.Set(reflect.MakeSlice(sliceInterfaceType, 0, 16))
} else if !elem.CanSet() {
nelem := reflect.New(sliceInterfaceType).Elem()
nelem.Set(reflect.MakeSlice(sliceInterfaceType, elem.Len(), elem.Cap()))
reflect.Copy(nelem, elem)
elem = nelem
}
}
err := d.unmarshalArray(array, elem)
if err != nil {
return err
}
v.Set(elem)
return nil
default:
// TODO: use newDecodeError, but first the parser needs to fill
// array.Data.
return d.typeMismatchError("array", v.Type())
}
elemType := v.Type().Elem()
it := array.Children()
idx := 0
for it.Next() {
n := it.Node()
// TODO: optimize
if v.Kind() == reflect.Slice {
elem := reflect.New(elemType).Elem()
err := d.handleValue(n, elem)
if err != nil {
return err
}
v.Set(reflect.Append(v, elem))
} else { // array
if idx >= v.Len() {
return nil
}
elem := v.Index(idx)
err := d.handleValue(n, elem)
if err != nil {
return err
}
idx++
}
}
return nil
}
func (d *decoder) unmarshalInlineTable(itable *ast.Node, v reflect.Value) error {
// Make sure v is an initialized object.
switch v.Kind() {
case reflect.Map:
if v.IsNil() {
v.Set(reflect.MakeMap(v.Type()))
}
case reflect.Struct:
// structs are always initialized.
case reflect.Interface:
elem := v.Elem()
if !elem.IsValid() {
elem = makeMapStringInterface()
v.Set(elem)
}
return d.unmarshalInlineTable(itable, elem)
default:
return newDecodeError(itable.Data, "cannot store inline table in Go type %s", v.Kind())
}
it := itable.Children()
for it.Next() {
n := it.Node()
x, err := d.handleKeyValue(n, v)
if err != nil {
return err
}
if x.IsValid() {
v = x
}
}
return nil
}
func (d *decoder) unmarshalDateTime(value *ast.Node, v reflect.Value) error {
dt, err := parseDateTime(value.Data)
if err != nil {
return err
}
v.Set(reflect.ValueOf(dt))
return nil
}
func (d *decoder) unmarshalLocalDate(value *ast.Node, v reflect.Value) error {
ld, err := parseLocalDate(value.Data)
if err != nil {
return err
}
if v.Type() == timeType {
cast := ld.AsTime(time.Local)
v.Set(reflect.ValueOf(cast))
return nil
}
v.Set(reflect.ValueOf(ld))
return nil
}
func (d *decoder) unmarshalLocalTime(value *ast.Node, v reflect.Value) error {
lt, rest, err := parseLocalTime(value.Data)
if err != nil {
return err
}
if len(rest) > 0 {
return newDecodeError(rest, "extra characters at the end of a local time")
}
v.Set(reflect.ValueOf(lt))
return nil
}
func (d *decoder) unmarshalLocalDateTime(value *ast.Node, v reflect.Value) error {
ldt, rest, err := parseLocalDateTime(value.Data)
if err != nil {
return err
}
if len(rest) > 0 {
return newDecodeError(rest, "extra characters at the end of a local date time")
}
if v.Type() == timeType {
cast := ldt.AsTime(time.Local)
v.Set(reflect.ValueOf(cast))
return nil
}
v.Set(reflect.ValueOf(ldt))
return nil
}
func (d *decoder) unmarshalBool(value *ast.Node, v reflect.Value) error {
b := value.Data[0] == 't'
switch v.Kind() {
case reflect.Bool:
v.SetBool(b)
case reflect.Interface:
v.Set(reflect.ValueOf(b))
default:
return newDecodeError(value.Data, "cannot assign boolean to a %t", b)
}
return nil
}
func (d *decoder) unmarshalFloat(value *ast.Node, v reflect.Value) error {
f, err := parseFloat(value.Data)
if err != nil {
return err
}
switch v.Kind() {
case reflect.Float64:
v.SetFloat(f)
case reflect.Float32:
if f > math.MaxFloat32 {
return newDecodeError(value.Data, "number %f does not fit in a float32", f)
}
v.SetFloat(f)
case reflect.Interface:
v.Set(reflect.ValueOf(f))
default:
return newDecodeError(value.Data, "float cannot be assigned to %s", v.Kind())
}
return nil
}
const (
maxInt = int64(^uint(0) >> 1)
minInt = -maxInt - 1
)
// Maximum value of uint for decoding. Currently the decoder parses the integer
// into an int64. As a result, on architectures where uint is 64 bits, the
// effective maximum uint we can decode is the maximum of int64. On
// architectures where uint is 32 bits, the maximum value we can decode is
// lower: the maximum of uint32. I didn't find a way to figure out this value at
// compile time, so it is computed during initialization.
var maxUint int64 = math.MaxInt64
func init() {
m := uint64(^uint(0))
if m < uint64(maxUint) {
maxUint = int64(m)
}
}
func (d *decoder) unmarshalInteger(value *ast.Node, v reflect.Value) error {
i, err := parseInteger(value.Data)
if err != nil {
return err
}
var r reflect.Value
switch v.Kind() {
case reflect.Int64:
v.SetInt(i)
return nil
case reflect.Int32:
if i < math.MinInt32 || i > math.MaxInt32 {
return fmt.Errorf("toml: number %d does not fit in an int32", i)
}
r = reflect.ValueOf(int32(i))
case reflect.Int16:
if i < math.MinInt16 || i > math.MaxInt16 {
return fmt.Errorf("toml: number %d does not fit in an int16", i)
}
r = reflect.ValueOf(int16(i))
case reflect.Int8:
if i < math.MinInt8 || i > math.MaxInt8 {
return fmt.Errorf("toml: number %d does not fit in an int8", i)
}
r = reflect.ValueOf(int8(i))
case reflect.Int:
if i < minInt || i > maxInt {
return fmt.Errorf("toml: number %d does not fit in an int", i)
}
r = reflect.ValueOf(int(i))
case reflect.Uint64:
if i < 0 {
return fmt.Errorf("toml: negative number %d does not fit in an uint64", i)
}
r = reflect.ValueOf(uint64(i))
case reflect.Uint32:
if i < 0 || i > math.MaxUint32 {
return fmt.Errorf("toml: negative number %d does not fit in an uint32", i)
}
r = reflect.ValueOf(uint32(i))
case reflect.Uint16:
if i < 0 || i > math.MaxUint16 {
return fmt.Errorf("toml: negative number %d does not fit in an uint16", i)
}
r = reflect.ValueOf(uint16(i))
case reflect.Uint8:
if i < 0 || i > math.MaxUint8 {
return fmt.Errorf("toml: negative number %d does not fit in an uint8", i)
}
r = reflect.ValueOf(uint8(i))
case reflect.Uint:
if i < 0 || i > maxUint {
return fmt.Errorf("toml: negative number %d does not fit in an uint", i)
}
r = reflect.ValueOf(uint(i))
case reflect.Interface:
r = reflect.ValueOf(i)
default:
return d.typeMismatchError("integer", v.Type())
}
if !r.Type().AssignableTo(v.Type()) {
r = r.Convert(v.Type())
}
v.Set(r)
return nil
}
func (d *decoder) unmarshalString(value *ast.Node, v reflect.Value) error {
switch v.Kind() {
case reflect.String:
v.SetString(string(value.Data))
case reflect.Interface:
v.Set(reflect.ValueOf(string(value.Data)))
default:
return newDecodeError(d.p.Raw(value.Raw), "cannot store TOML string into a Go %s", v.Kind())
}
return nil
}
func (d *decoder) handleKeyValue(expr *ast.Node, v reflect.Value) (reflect.Value, error) {
d.strict.EnterKeyValue(expr)
v, err := d.handleKeyValueInner(expr.Key(), expr.Value(), v)
if d.skipUntilTable {
d.strict.MissingField(expr)
d.skipUntilTable = false
}
d.strict.ExitKeyValue(expr)
return v, err
}
func (d *decoder) handleKeyValueInner(key ast.Iterator, value *ast.Node, v reflect.Value) (reflect.Value, error) {
if key.Next() {
// Still scoping the key
return d.handleKeyValuePart(key, value, v)
}
// Done scoping the key.
// v is whatever Go value we need to fill.
return reflect.Value{}, d.handleValue(value, v)
}
func (d *decoder) handleKeyValuePart(key ast.Iterator, value *ast.Node, v reflect.Value) (reflect.Value, error) {
// contains the replacement for v
var rv reflect.Value
// First, dispatch over v to make sure it is a valid object.
// There is no guarantee over what it could be.
switch v.Kind() {
case reflect.Map:
vt := v.Type()
mk := reflect.ValueOf(string(key.Node().Data))
mkt := stringType
keyType := vt.Key()
if !mkt.AssignableTo(keyType) {
if !mkt.ConvertibleTo(keyType) {
return reflect.Value{}, fmt.Errorf("toml: cannot convert map key of type %s to expected type %s", mkt, keyType)
}
mk = mk.Convert(keyType)
}
// If the map does not exist, create it.
if v.IsNil() {
v = reflect.MakeMap(vt)
rv = v
}
mv := v.MapIndex(mk)
set := false
if !mv.IsValid() {
set = true
mv = reflect.New(v.Type().Elem()).Elem()
} else {
if key.IsLast() {
var x interface{}
mv = reflect.ValueOf(&x).Elem()
set = true
}
}
nv, err := d.handleKeyValueInner(key, value, mv)
if err != nil {
return reflect.Value{}, err
}
if nv.IsValid() {
mv = nv
set = true
}
if set {
v.SetMapIndex(mk, mv)
}
case reflect.Struct:
path, found := structFieldPath(v, string(key.Node().Data))
if !found {
d.skipUntilTable = true
break
}
if d.errorContext == nil {
d.errorContext = new(errorContext)
}
t := v.Type()
d.errorContext.Struct = t
d.errorContext.Field = path
f := fieldByIndex(v, path)
x, err := d.handleKeyValueInner(key, value, f)
if err != nil {
return reflect.Value{}, err
}
if x.IsValid() {
f.Set(x)
}
d.errorContext.Struct = nil
d.errorContext.Field = nil
case reflect.Interface:
v = v.Elem()
// Following encoding/json: decoding an object into an
// interface{}, it needs to always hold a
// map[string]interface{}. This is for the types to be
// consistent whether a previous value was set or not.
if !v.IsValid() || v.Type() != mapStringInterfaceType {
v = makeMapStringInterface()
}
x, err := d.handleKeyValuePart(key, value, v)
if err != nil {
return reflect.Value{}, err
}
if x.IsValid() {
v = x
}
rv = v
case reflect.Ptr:
elem := v.Elem()
if !elem.IsValid() {
ptr := reflect.New(v.Type().Elem())
v.Set(ptr)
rv = v
elem = ptr.Elem()
}
elem2, err := d.handleKeyValuePart(key, value, elem)
if err != nil {
return reflect.Value{}, err
}
if elem2.IsValid() {
elem = elem2
}
v.Elem().Set(elem)
default:
return reflect.Value{}, fmt.Errorf("unhandled kv part: %s", v.Kind())
}
return rv, nil
}
func initAndDereferencePointer(v reflect.Value) reflect.Value {
var elem reflect.Value
if v.IsNil() {
ptr := reflect.New(v.Type().Elem())
v.Set(ptr)
}
elem = v.Elem()
return elem
}
// Same as reflect.Value.FieldByIndex, but creates pointers if needed.
func fieldByIndex(v reflect.Value, path []int) reflect.Value {
for i, x := range path {
v = v.Field(x)
if i < len(path)-1 && v.Kind() == reflect.Ptr {
if v.IsNil() {
v.Set(reflect.New(v.Type().Elem()))
}
v = v.Elem()
}
}
return v
}
type fieldPathsMap = map[string][]int
var globalFieldPathsCache atomic.Value // map[danger.TypeID]fieldPathsMap
func structFieldPath(v reflect.Value, name string) ([]int, bool) {
t := v.Type()
cache, _ := globalFieldPathsCache.Load().(map[danger.TypeID]fieldPathsMap)
fieldPaths, ok := cache[danger.MakeTypeID(t)]
if !ok {
fieldPaths = map[string][]int{}
forEachField(t, nil, func(name string, path []int) {
fieldPaths[name] = path
// extra copy for the case-insensitive match
fieldPaths[strings.ToLower(name)] = path
})
newCache := make(map[danger.TypeID]fieldPathsMap, len(cache)+1)
newCache[danger.MakeTypeID(t)] = fieldPaths
for k, v := range cache {
newCache[k] = v
}
globalFieldPathsCache.Store(newCache)
}
path, ok := fieldPaths[name]
if !ok {
path, ok = fieldPaths[strings.ToLower(name)]
}
return path, ok
}
func forEachField(t reflect.Type, path []int, do func(name string, path []int)) {
n := t.NumField()
for i := 0; i < n; i++ {
f := t.Field(i)
if !f.Anonymous && f.PkgPath != "" {
// only consider exported fields.
continue
}
fieldPath := append(path, i)
fieldPath = fieldPath[:len(fieldPath):len(fieldPath)]
name := f.Tag.Get("toml")
if name == "-" {
continue
}
if i := strings.IndexByte(name, ','); i >= 0 {
name = name[:i]
}
if f.Anonymous && name == "" {
t2 := f.Type
if t2.Kind() == reflect.Ptr {
t2 = t2.Elem()
}
if t2.Kind() == reflect.Struct {
forEachField(t2, fieldPath, do)
}
continue
}
if name == "" {
name = f.Name
}
do(name, fieldPath)
}
}