mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-28 05:57:25 +00:00
Bump github.com/mitchellh/mapstructure
This commit is contained in:
parent
ca1f844bc8
commit
122ed986cb
2
Godeps/Godeps.json
generated
2
Godeps/Godeps.json
generated
@ -1779,7 +1779,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/mitchellh/mapstructure",
|
"ImportPath": "github.com/mitchellh/mapstructure",
|
||||||
"Rev": "740c764bc6149d3f1806231418adb9f52c11bcbf"
|
"Rev": "53818660ed4955e899c0bcafa97299a388bd7c8e"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/mreiferson/go-httpclient",
|
"ImportPath": "github.com/mreiferson/go-httpclient",
|
||||||
|
7
vendor/github.com/mitchellh/mapstructure/.travis.yml
generated
vendored
Normal file
7
vendor/github.com/mitchellh/mapstructure/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
language: go
|
||||||
|
|
||||||
|
go:
|
||||||
|
- 1.4
|
||||||
|
|
||||||
|
script:
|
||||||
|
- go test
|
78
vendor/github.com/mitchellh/mapstructure/decode_hooks.go
generated
vendored
78
vendor/github.com/mitchellh/mapstructure/decode_hooks.go
generated
vendored
@ -1,11 +1,59 @@
|
|||||||
package mapstructure
|
package mapstructure
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// typedDecodeHook takes a raw DecodeHookFunc (an interface{}) and turns
|
||||||
|
// it into the proper DecodeHookFunc type, such as DecodeHookFuncType.
|
||||||
|
func typedDecodeHook(h DecodeHookFunc) DecodeHookFunc {
|
||||||
|
// Create variables here so we can reference them with the reflect pkg
|
||||||
|
var f1 DecodeHookFuncType
|
||||||
|
var f2 DecodeHookFuncKind
|
||||||
|
|
||||||
|
// Fill in the variables into this interface and the rest is done
|
||||||
|
// automatically using the reflect package.
|
||||||
|
potential := []interface{}{f1, f2}
|
||||||
|
|
||||||
|
v := reflect.ValueOf(h)
|
||||||
|
vt := v.Type()
|
||||||
|
for _, raw := range potential {
|
||||||
|
pt := reflect.ValueOf(raw).Type()
|
||||||
|
if vt.ConvertibleTo(pt) {
|
||||||
|
return v.Convert(pt).Interface()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeHookExec executes the given decode hook. This should be used
|
||||||
|
// since it'll naturally degrade to the older backwards compatible DecodeHookFunc
|
||||||
|
// that took reflect.Kind instead of reflect.Type.
|
||||||
|
func DecodeHookExec(
|
||||||
|
raw DecodeHookFunc,
|
||||||
|
from reflect.Type, to reflect.Type,
|
||||||
|
data interface{}) (interface{}, error) {
|
||||||
|
// Build our arguments that reflect expects
|
||||||
|
argVals := make([]reflect.Value, 3)
|
||||||
|
argVals[0] = reflect.ValueOf(from)
|
||||||
|
argVals[1] = reflect.ValueOf(to)
|
||||||
|
argVals[2] = reflect.ValueOf(data)
|
||||||
|
|
||||||
|
switch f := typedDecodeHook(raw).(type) {
|
||||||
|
case DecodeHookFuncType:
|
||||||
|
return f(from, to, data)
|
||||||
|
case DecodeHookFuncKind:
|
||||||
|
return f(from.Kind(), to.Kind(), data)
|
||||||
|
default:
|
||||||
|
return nil, errors.New("invalid decode hook signature")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ComposeDecodeHookFunc creates a single DecodeHookFunc that
|
// ComposeDecodeHookFunc creates a single DecodeHookFunc that
|
||||||
// automatically composes multiple DecodeHookFuncs.
|
// automatically composes multiple DecodeHookFuncs.
|
||||||
//
|
//
|
||||||
@ -13,18 +61,21 @@ import (
|
|||||||
// previous transformation.
|
// previous transformation.
|
||||||
func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc {
|
func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc {
|
||||||
return func(
|
return func(
|
||||||
f reflect.Kind,
|
f reflect.Type,
|
||||||
t reflect.Kind,
|
t reflect.Type,
|
||||||
data interface{}) (interface{}, error) {
|
data interface{}) (interface{}, error) {
|
||||||
var err error
|
var err error
|
||||||
for _, f1 := range fs {
|
for _, f1 := range fs {
|
||||||
data, err = f1(f, t, data)
|
data, err = DecodeHookExec(f1, f, t, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Modify the from kind to be correct with the new data
|
// Modify the from kind to be correct with the new data
|
||||||
f = getKind(reflect.ValueOf(data))
|
f = nil
|
||||||
|
if val := reflect.ValueOf(data); val.IsValid() {
|
||||||
|
f = val.Type()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return data, nil
|
return data, nil
|
||||||
@ -51,6 +102,25 @@ func StringToSliceHookFunc(sep string) DecodeHookFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StringToTimeDurationHookFunc returns a DecodeHookFunc that converts
|
||||||
|
// strings to time.Duration.
|
||||||
|
func StringToTimeDurationHookFunc() DecodeHookFunc {
|
||||||
|
return func(
|
||||||
|
f reflect.Type,
|
||||||
|
t reflect.Type,
|
||||||
|
data interface{}) (interface{}, error) {
|
||||||
|
if f.Kind() != reflect.String {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
if t != reflect.TypeOf(time.Duration(5)) {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert it by parsing
|
||||||
|
return time.ParseDuration(data.(string))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func WeaklyTypedHook(
|
func WeaklyTypedHook(
|
||||||
f reflect.Kind,
|
f reflect.Kind,
|
||||||
t reflect.Kind,
|
t reflect.Kind,
|
||||||
|
18
vendor/github.com/mitchellh/mapstructure/error.go
generated
vendored
18
vendor/github.com/mitchellh/mapstructure/error.go
generated
vendored
@ -1,7 +1,9 @@
|
|||||||
package mapstructure
|
package mapstructure
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -17,11 +19,27 @@ func (e *Error) Error() string {
|
|||||||
points[i] = fmt.Sprintf("* %s", err)
|
points[i] = fmt.Sprintf("* %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sort.Strings(points)
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
"%d error(s) decoding:\n\n%s",
|
"%d error(s) decoding:\n\n%s",
|
||||||
len(e.Errors), strings.Join(points, "\n"))
|
len(e.Errors), strings.Join(points, "\n"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WrappedErrors implements the errwrap.Wrapper interface to make this
|
||||||
|
// return value more useful with the errwrap and go-multierror libraries.
|
||||||
|
func (e *Error) WrappedErrors() []error {
|
||||||
|
if e == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
result := make([]error, len(e.Errors))
|
||||||
|
for i, e := range e.Errors {
|
||||||
|
result[i] = errors.New(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
func appendErrors(errors []string, err error) []string {
|
func appendErrors(errors []string, err error) []string {
|
||||||
switch e := err.(type) {
|
switch e := err.(type) {
|
||||||
case *Error:
|
case *Error:
|
||||||
|
191
vendor/github.com/mitchellh/mapstructure/mapstructure.go
generated
vendored
191
vendor/github.com/mitchellh/mapstructure/mapstructure.go
generated
vendored
@ -1,5 +1,5 @@
|
|||||||
// The mapstructure package exposes functionality to convert an
|
// The mapstructure package exposes functionality to convert an
|
||||||
// abitrary map[string]interface{} into a native Go structure.
|
// arbitrary map[string]interface{} into a native Go structure.
|
||||||
//
|
//
|
||||||
// The Go structure can be arbitrarily complex, containing slices,
|
// The Go structure can be arbitrarily complex, containing slices,
|
||||||
// other structs, etc. and the decoder will properly decode nested
|
// other structs, etc. and the decoder will properly decode nested
|
||||||
@ -8,6 +8,7 @@
|
|||||||
package mapstructure
|
package mapstructure
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
@ -19,10 +20,20 @@ import (
|
|||||||
// DecodeHookFunc is the callback function that can be used for
|
// DecodeHookFunc is the callback function that can be used for
|
||||||
// data transformations. See "DecodeHook" in the DecoderConfig
|
// data transformations. See "DecodeHook" in the DecoderConfig
|
||||||
// struct.
|
// struct.
|
||||||
type DecodeHookFunc func(
|
//
|
||||||
from reflect.Kind,
|
// The type should be DecodeHookFuncType or DecodeHookFuncKind.
|
||||||
to reflect.Kind,
|
// Either is accepted. Types are a superset of Kinds (Types can return
|
||||||
data interface{}) (interface{}, error)
|
// Kinds) and are generally a richer thing to use, but Kinds are simpler
|
||||||
|
// if you only need those.
|
||||||
|
//
|
||||||
|
// The reason DecodeHookFunc is multi-typed is for backwards compatibility:
|
||||||
|
// we started with Kinds and then realized Types were the better solution,
|
||||||
|
// but have a promise to not break backwards compat so we now support
|
||||||
|
// both.
|
||||||
|
type DecodeHookFunc interface{}
|
||||||
|
|
||||||
|
type DecodeHookFuncType func(reflect.Type, reflect.Type, interface{}) (interface{}, error)
|
||||||
|
type DecodeHookFuncKind func(reflect.Kind, reflect.Kind, interface{}) (interface{}, error)
|
||||||
|
|
||||||
// DecoderConfig is the configuration that is used to create a new decoder
|
// DecoderConfig is the configuration that is used to create a new decoder
|
||||||
// and allows customization of various aspects of decoding.
|
// and allows customization of various aspects of decoding.
|
||||||
@ -40,6 +51,11 @@ type DecoderConfig struct {
|
|||||||
// (extra keys).
|
// (extra keys).
|
||||||
ErrorUnused bool
|
ErrorUnused bool
|
||||||
|
|
||||||
|
// ZeroFields, if set to true, will zero fields before writing them.
|
||||||
|
// For example, a map will be emptied before decoded values are put in
|
||||||
|
// it. If this is false, a map will be merged.
|
||||||
|
ZeroFields bool
|
||||||
|
|
||||||
// If WeaklyTypedInput is true, the decoder will make the following
|
// If WeaklyTypedInput is true, the decoder will make the following
|
||||||
// "weak" conversions:
|
// "weak" conversions:
|
||||||
//
|
//
|
||||||
@ -51,6 +67,11 @@ type DecoderConfig struct {
|
|||||||
// - string to bool (accepts: 1, t, T, TRUE, true, True, 0, f, F,
|
// - string to bool (accepts: 1, t, T, TRUE, true, True, 0, f, F,
|
||||||
// FALSE, false, False. Anything else is an error)
|
// FALSE, false, False. Anything else is an error)
|
||||||
// - empty array = empty map and vice versa
|
// - empty array = empty map and vice versa
|
||||||
|
// - negative numbers to overflowed uint values (base 10)
|
||||||
|
// - slice of maps to a merged map
|
||||||
|
// - single values are converted to slices if required. Each
|
||||||
|
// element is weakly decoded. For example: "4" can become []int{4}
|
||||||
|
// if the target type is an int slice.
|
||||||
//
|
//
|
||||||
WeaklyTypedInput bool
|
WeaklyTypedInput bool
|
||||||
|
|
||||||
@ -180,9 +201,11 @@ func (d *Decoder) decode(name string, data interface{}, val reflect.Value) error
|
|||||||
if d.config.DecodeHook != nil {
|
if d.config.DecodeHook != nil {
|
||||||
// We have a DecodeHook, so let's pre-process the data.
|
// We have a DecodeHook, so let's pre-process the data.
|
||||||
var err error
|
var err error
|
||||||
data, err = d.config.DecodeHook(getKind(dataVal), getKind(val), data)
|
data, err = DecodeHookExec(
|
||||||
|
d.config.DecodeHook,
|
||||||
|
dataVal.Type(), val.Type(), data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("error decoding '%s': %s", name, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,6 +232,8 @@ func (d *Decoder) decode(name string, data interface{}, val reflect.Value) error
|
|||||||
err = d.decodePtr(name, data, val)
|
err = d.decodePtr(name, data, val)
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
err = d.decodeSlice(name, data, val)
|
err = d.decodeSlice(name, data, val)
|
||||||
|
case reflect.Func:
|
||||||
|
err = d.decodeFunc(name, data, val)
|
||||||
default:
|
default:
|
||||||
// If we reached this point then we weren't able to decode it
|
// If we reached this point then we weren't able to decode it
|
||||||
return fmt.Errorf("%s: unsupported type: %s", name, dataKind)
|
return fmt.Errorf("%s: unsupported type: %s", name, dataKind)
|
||||||
@ -227,6 +252,10 @@ func (d *Decoder) decode(name string, data interface{}, val reflect.Value) error
|
|||||||
// value to "data" of that type.
|
// value to "data" of that type.
|
||||||
func (d *Decoder) decodeBasic(name string, data interface{}, val reflect.Value) error {
|
func (d *Decoder) decodeBasic(name string, data interface{}, val reflect.Value) error {
|
||||||
dataVal := reflect.ValueOf(data)
|
dataVal := reflect.ValueOf(data)
|
||||||
|
if !dataVal.IsValid() {
|
||||||
|
dataVal = reflect.Zero(val.Type())
|
||||||
|
}
|
||||||
|
|
||||||
dataValType := dataVal.Type()
|
dataValType := dataVal.Type()
|
||||||
if !dataValType.AssignableTo(val.Type()) {
|
if !dataValType.AssignableTo(val.Type()) {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
@ -283,6 +312,7 @@ func (d *Decoder) decodeString(name string, data interface{}, val reflect.Value)
|
|||||||
func (d *Decoder) decodeInt(name string, data interface{}, val reflect.Value) error {
|
func (d *Decoder) decodeInt(name string, data interface{}, val reflect.Value) error {
|
||||||
dataVal := reflect.ValueOf(data)
|
dataVal := reflect.ValueOf(data)
|
||||||
dataKind := getKind(dataVal)
|
dataKind := getKind(dataVal)
|
||||||
|
dataType := dataVal.Type()
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case dataKind == reflect.Int:
|
case dataKind == reflect.Int:
|
||||||
@ -304,6 +334,14 @@ func (d *Decoder) decodeInt(name string, data interface{}, val reflect.Value) er
|
|||||||
} else {
|
} else {
|
||||||
return fmt.Errorf("cannot parse '%s' as int: %s", name, err)
|
return fmt.Errorf("cannot parse '%s' as int: %s", name, err)
|
||||||
}
|
}
|
||||||
|
case dataType.PkgPath() == "encoding/json" && dataType.Name() == "Number":
|
||||||
|
jn := data.(json.Number)
|
||||||
|
i, err := jn.Int64()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"error decoding json.Number into %s: %s", name, err)
|
||||||
|
}
|
||||||
|
val.SetInt(i)
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"'%s' expected type '%s', got unconvertible type '%s'",
|
"'%s' expected type '%s', got unconvertible type '%s'",
|
||||||
@ -319,11 +357,21 @@ func (d *Decoder) decodeUint(name string, data interface{}, val reflect.Value) e
|
|||||||
|
|
||||||
switch {
|
switch {
|
||||||
case dataKind == reflect.Int:
|
case dataKind == reflect.Int:
|
||||||
val.SetUint(uint64(dataVal.Int()))
|
i := dataVal.Int()
|
||||||
|
if i < 0 && !d.config.WeaklyTypedInput {
|
||||||
|
return fmt.Errorf("cannot parse '%s', %d overflows uint",
|
||||||
|
name, i)
|
||||||
|
}
|
||||||
|
val.SetUint(uint64(i))
|
||||||
case dataKind == reflect.Uint:
|
case dataKind == reflect.Uint:
|
||||||
val.SetUint(dataVal.Uint())
|
val.SetUint(dataVal.Uint())
|
||||||
case dataKind == reflect.Float32:
|
case dataKind == reflect.Float32:
|
||||||
val.SetUint(uint64(dataVal.Float()))
|
f := dataVal.Float()
|
||||||
|
if f < 0 && !d.config.WeaklyTypedInput {
|
||||||
|
return fmt.Errorf("cannot parse '%s', %f overflows uint",
|
||||||
|
name, f)
|
||||||
|
}
|
||||||
|
val.SetUint(uint64(f))
|
||||||
case dataKind == reflect.Bool && d.config.WeaklyTypedInput:
|
case dataKind == reflect.Bool && d.config.WeaklyTypedInput:
|
||||||
if dataVal.Bool() {
|
if dataVal.Bool() {
|
||||||
val.SetUint(1)
|
val.SetUint(1)
|
||||||
@ -380,6 +428,7 @@ func (d *Decoder) decodeBool(name string, data interface{}, val reflect.Value) e
|
|||||||
func (d *Decoder) decodeFloat(name string, data interface{}, val reflect.Value) error {
|
func (d *Decoder) decodeFloat(name string, data interface{}, val reflect.Value) error {
|
||||||
dataVal := reflect.ValueOf(data)
|
dataVal := reflect.ValueOf(data)
|
||||||
dataKind := getKind(dataVal)
|
dataKind := getKind(dataVal)
|
||||||
|
dataType := dataVal.Type()
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case dataKind == reflect.Int:
|
case dataKind == reflect.Int:
|
||||||
@ -401,6 +450,14 @@ func (d *Decoder) decodeFloat(name string, data interface{}, val reflect.Value)
|
|||||||
} else {
|
} else {
|
||||||
return fmt.Errorf("cannot parse '%s' as float: %s", name, err)
|
return fmt.Errorf("cannot parse '%s' as float: %s", name, err)
|
||||||
}
|
}
|
||||||
|
case dataType.PkgPath() == "encoding/json" && dataType.Name() == "Number":
|
||||||
|
jn := data.(json.Number)
|
||||||
|
i, err := jn.Float64()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"error decoding json.Number into %s: %s", name, err)
|
||||||
|
}
|
||||||
|
val.SetFloat(i)
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"'%s' expected type '%s', got unconvertible type '%s'",
|
"'%s' expected type '%s', got unconvertible type '%s'",
|
||||||
@ -415,22 +472,43 @@ func (d *Decoder) decodeMap(name string, data interface{}, val reflect.Value) er
|
|||||||
valKeyType := valType.Key()
|
valKeyType := valType.Key()
|
||||||
valElemType := valType.Elem()
|
valElemType := valType.Elem()
|
||||||
|
|
||||||
|
// By default we overwrite keys in the current map
|
||||||
|
valMap := val
|
||||||
|
|
||||||
|
// If the map is nil or we're purposely zeroing fields, make a new map
|
||||||
|
if valMap.IsNil() || d.config.ZeroFields {
|
||||||
// Make a new map to hold our result
|
// Make a new map to hold our result
|
||||||
mapType := reflect.MapOf(valKeyType, valElemType)
|
mapType := reflect.MapOf(valKeyType, valElemType)
|
||||||
valMap := reflect.MakeMap(mapType)
|
valMap = reflect.MakeMap(mapType)
|
||||||
|
}
|
||||||
|
|
||||||
// Check input type
|
// Check input type
|
||||||
dataVal := reflect.Indirect(reflect.ValueOf(data))
|
dataVal := reflect.Indirect(reflect.ValueOf(data))
|
||||||
if dataVal.Kind() != reflect.Map {
|
if dataVal.Kind() != reflect.Map {
|
||||||
// Accept empty array/slice instead of an empty map in weakly typed mode
|
// In weak mode, we accept a slice of maps as an input...
|
||||||
if d.config.WeaklyTypedInput &&
|
if d.config.WeaklyTypedInput {
|
||||||
(dataVal.Kind() == reflect.Slice || dataVal.Kind() == reflect.Array) &&
|
switch dataVal.Kind() {
|
||||||
dataVal.Len() == 0 {
|
case reflect.Array, reflect.Slice:
|
||||||
|
// Special case for BC reasons (covered by tests)
|
||||||
|
if dataVal.Len() == 0 {
|
||||||
val.Set(valMap)
|
val.Set(valMap)
|
||||||
return nil
|
return nil
|
||||||
} else {
|
|
||||||
return fmt.Errorf("'%s' expected a map, got '%s'", name, dataVal.Kind())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for i := 0; i < dataVal.Len(); i++ {
|
||||||
|
err := d.decode(
|
||||||
|
fmt.Sprintf("%s[%d]", name, i),
|
||||||
|
dataVal.Index(i).Interface(), val)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("'%s' expected a map, got '%s'", name, dataVal.Kind())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accumulate errors
|
// Accumulate errors
|
||||||
@ -473,7 +551,12 @@ func (d *Decoder) decodePtr(name string, data interface{}, val reflect.Value) er
|
|||||||
// into that. Then set the value of the pointer to this type.
|
// into that. Then set the value of the pointer to this type.
|
||||||
valType := val.Type()
|
valType := val.Type()
|
||||||
valElemType := valType.Elem()
|
valElemType := valType.Elem()
|
||||||
realVal := reflect.New(valElemType)
|
|
||||||
|
realVal := val
|
||||||
|
if realVal.IsNil() || d.config.ZeroFields {
|
||||||
|
realVal = reflect.New(valElemType)
|
||||||
|
}
|
||||||
|
|
||||||
if err := d.decode(name, data, reflect.Indirect(realVal)); err != nil {
|
if err := d.decode(name, data, reflect.Indirect(realVal)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -482,6 +565,19 @@ func (d *Decoder) decodePtr(name string, data interface{}, val reflect.Value) er
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) decodeFunc(name string, data interface{}, val reflect.Value) error {
|
||||||
|
// Create an element of the concrete (non pointer) type and decode
|
||||||
|
// into that. Then set the value of the pointer to this type.
|
||||||
|
dataVal := reflect.Indirect(reflect.ValueOf(data))
|
||||||
|
if val.Type() != dataVal.Type() {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"'%s' expected type '%s', got unconvertible type '%s'",
|
||||||
|
name, val.Type(), dataVal.Type())
|
||||||
|
}
|
||||||
|
val.Set(dataVal)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value) error {
|
func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value) error {
|
||||||
dataVal := reflect.Indirect(reflect.ValueOf(data))
|
dataVal := reflect.Indirect(reflect.ValueOf(data))
|
||||||
dataValKind := dataVal.Kind()
|
dataValKind := dataVal.Kind()
|
||||||
@ -489,26 +585,44 @@ func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value)
|
|||||||
valElemType := valType.Elem()
|
valElemType := valType.Elem()
|
||||||
sliceType := reflect.SliceOf(valElemType)
|
sliceType := reflect.SliceOf(valElemType)
|
||||||
|
|
||||||
|
valSlice := val
|
||||||
|
if valSlice.IsNil() || d.config.ZeroFields {
|
||||||
// Check input type
|
// Check input type
|
||||||
if dataValKind != reflect.Array && dataValKind != reflect.Slice {
|
if dataValKind != reflect.Array && dataValKind != reflect.Slice {
|
||||||
// Accept empty map instead of array/slice in weakly typed mode
|
if d.config.WeaklyTypedInput {
|
||||||
if d.config.WeaklyTypedInput && dataVal.Kind() == reflect.Map && dataVal.Len() == 0 {
|
switch {
|
||||||
|
// Empty maps turn into empty slices
|
||||||
|
case dataValKind == reflect.Map:
|
||||||
|
if dataVal.Len() == 0 {
|
||||||
val.Set(reflect.MakeSlice(sliceType, 0, 0))
|
val.Set(reflect.MakeSlice(sliceType, 0, 0))
|
||||||
return nil
|
return nil
|
||||||
} else {
|
}
|
||||||
return fmt.Errorf(
|
|
||||||
"'%s': source data must be an array or slice, got %s", name, dataValKind)
|
// All other types we try to convert to the slice type
|
||||||
|
// and "lift" it into it. i.e. a string becomes a string slice.
|
||||||
|
default:
|
||||||
|
// Just re-try this function with data as a slice.
|
||||||
|
return d.decodeSlice(name, []interface{}{data}, val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf(
|
||||||
|
"'%s': source data must be an array or slice, got %s", name, dataValKind)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// Make a new slice to hold our result, same size as the original data.
|
// Make a new slice to hold our result, same size as the original data.
|
||||||
valSlice := reflect.MakeSlice(sliceType, dataVal.Len(), dataVal.Len())
|
valSlice = reflect.MakeSlice(sliceType, dataVal.Len(), dataVal.Len())
|
||||||
|
}
|
||||||
|
|
||||||
// Accumulate any errors
|
// Accumulate any errors
|
||||||
errors := make([]string, 0)
|
errors := make([]string, 0)
|
||||||
|
|
||||||
for i := 0; i < dataVal.Len(); i++ {
|
for i := 0; i < dataVal.Len(); i++ {
|
||||||
currentData := dataVal.Index(i).Interface()
|
currentData := dataVal.Index(i).Interface()
|
||||||
|
for valSlice.Len() <= i {
|
||||||
|
valSlice = reflect.Append(valSlice, reflect.Zero(valElemType))
|
||||||
|
}
|
||||||
currentField := valSlice.Index(i)
|
currentField := valSlice.Index(i)
|
||||||
|
|
||||||
fieldName := fmt.Sprintf("%s[%d]", name, i)
|
fieldName := fmt.Sprintf("%s[%d]", name, i)
|
||||||
@ -530,6 +644,14 @@ func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value)
|
|||||||
|
|
||||||
func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value) error {
|
func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value) error {
|
||||||
dataVal := reflect.Indirect(reflect.ValueOf(data))
|
dataVal := reflect.Indirect(reflect.ValueOf(data))
|
||||||
|
|
||||||
|
// If the type of the value to write to and the data match directly,
|
||||||
|
// then we just set it directly instead of recursing into the structure.
|
||||||
|
if dataVal.Type() == val.Type() {
|
||||||
|
val.Set(dataVal)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
dataValKind := dataVal.Kind()
|
dataValKind := dataVal.Kind()
|
||||||
if dataValKind != reflect.Map {
|
if dataValKind != reflect.Map {
|
||||||
return fmt.Errorf("'%s' expected a map, got '%s'", name, dataValKind)
|
return fmt.Errorf("'%s' expected a map, got '%s'", name, dataValKind)
|
||||||
@ -565,19 +687,12 @@ func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value)
|
|||||||
structs = structs[1:]
|
structs = structs[1:]
|
||||||
|
|
||||||
structType := structVal.Type()
|
structType := structVal.Type()
|
||||||
|
|
||||||
for i := 0; i < structType.NumField(); i++ {
|
for i := 0; i < structType.NumField(); i++ {
|
||||||
fieldType := structType.Field(i)
|
fieldType := structType.Field(i)
|
||||||
|
|
||||||
if fieldType.Anonymous {
|
|
||||||
fieldKind := fieldType.Type.Kind()
|
fieldKind := fieldType.Type.Kind()
|
||||||
if fieldKind != reflect.Struct {
|
|
||||||
errors = appendErrors(errors,
|
|
||||||
fmt.Errorf("%s: unsupported type: %s", fieldType.Name, fieldKind))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// We have an embedded field. We "squash" the fields down
|
// If "squash" is specified in the tag, we squash the field down.
|
||||||
// if specified in the tag.
|
|
||||||
squash := false
|
squash := false
|
||||||
tagParts := strings.Split(fieldType.Tag.Get(d.config.TagName), ",")
|
tagParts := strings.Split(fieldType.Tag.Get(d.config.TagName), ",")
|
||||||
for _, tag := range tagParts[1:] {
|
for _, tag := range tagParts[1:] {
|
||||||
@ -588,9 +703,13 @@ func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if squash {
|
if squash {
|
||||||
|
if fieldKind != reflect.Struct {
|
||||||
|
errors = appendErrors(errors,
|
||||||
|
fmt.Errorf("%s: unsupported type for squash: %s", fieldType.Name, fieldKind))
|
||||||
|
} else {
|
||||||
structs = append(structs, val.FieldByName(fieldType.Name))
|
structs = append(structs, val.FieldByName(fieldType.Name))
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normal struct field, store it away
|
// Normal struct field, store it away
|
||||||
@ -612,7 +731,7 @@ func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value)
|
|||||||
if !rawMapVal.IsValid() {
|
if !rawMapVal.IsValid() {
|
||||||
// Do a slower search by iterating over each key and
|
// Do a slower search by iterating over each key and
|
||||||
// doing case-insensitive search.
|
// doing case-insensitive search.
|
||||||
for dataValKey, _ := range dataValKeys {
|
for dataValKey := range dataValKeys {
|
||||||
mK, ok := dataValKey.Interface().(string)
|
mK, ok := dataValKey.Interface().(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
// Not a string key
|
// Not a string key
|
||||||
@ -660,7 +779,7 @@ func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value)
|
|||||||
|
|
||||||
if d.config.ErrorUnused && len(dataValKeysUnused) > 0 {
|
if d.config.ErrorUnused && len(dataValKeysUnused) > 0 {
|
||||||
keys := make([]string, 0, len(dataValKeysUnused))
|
keys := make([]string, 0, len(dataValKeysUnused))
|
||||||
for rawKey, _ := range dataValKeysUnused {
|
for rawKey := range dataValKeysUnused {
|
||||||
keys = append(keys, rawKey.(string))
|
keys = append(keys, rawKey.(string))
|
||||||
}
|
}
|
||||||
sort.Strings(keys)
|
sort.Strings(keys)
|
||||||
@ -675,7 +794,7 @@ func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value)
|
|||||||
|
|
||||||
// Add the unused keys to the list of unused keys if we're tracking metadata
|
// Add the unused keys to the list of unused keys if we're tracking metadata
|
||||||
if d.config.Metadata != nil {
|
if d.config.Metadata != nil {
|
||||||
for rawKey, _ := range dataValKeysUnused {
|
for rawKey := range dataValKeysUnused {
|
||||||
key := rawKey.(string)
|
key := rawKey.(string)
|
||||||
if name != "" {
|
if name != "" {
|
||||||
key = fmt.Sprintf("%s.%s", name, key)
|
key = fmt.Sprintf("%s.%s", name, key)
|
||||||
|
Loading…
Reference in New Issue
Block a user