aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/go-viper/mapstructure/v2/mapstructure.go
diff options
context:
space:
mode:
authorTaras Madan <tarasmadan@google.com>2024-09-10 12:16:33 +0200
committerTaras Madan <tarasmadan@google.com>2024-09-10 14:05:26 +0000
commitc97c816133b42257d0bcf1ee4bd178bb2a7a2b9e (patch)
tree0bcbc2e540bbf8f62f6c17887cdd53b8c2cee637 /vendor/github.com/go-viper/mapstructure/v2/mapstructure.go
parent54e657429ab892ad06c90cd7c1a4eb33ba93a3dc (diff)
vendor: update
Diffstat (limited to 'vendor/github.com/go-viper/mapstructure/v2/mapstructure.go')
-rw-r--r--vendor/github.com/go-viper/mapstructure/v2/mapstructure.go117
1 files changed, 74 insertions, 43 deletions
diff --git a/vendor/github.com/go-viper/mapstructure/v2/mapstructure.go b/vendor/github.com/go-viper/mapstructure/v2/mapstructure.go
index 27f21bc72..1cd6204bb 100644
--- a/vendor/github.com/go-viper/mapstructure/v2/mapstructure.go
+++ b/vendor/github.com/go-viper/mapstructure/v2/mapstructure.go
@@ -160,12 +160,13 @@ package mapstructure
import (
"encoding/json"
- "errors"
"fmt"
"reflect"
"sort"
"strconv"
"strings"
+
+ "github.com/go-viper/mapstructure/v2/internal/errors"
)
// DecodeHookFunc is the callback function that can be used for
@@ -265,6 +266,10 @@ type DecoderConfig struct {
// defaults to "mapstructure"
TagName string
+ // The option of the value in the tag that indicates a field should
+ // be squashed. This defaults to "squash".
+ SquashTagOption string
+
// IgnoreUntaggedFields ignores all struct fields without explicit
// TagName, comparable to `mapstructure:"-"` as default behaviour.
IgnoreUntaggedFields bool
@@ -282,7 +287,8 @@ type DecoderConfig struct {
// structure. The top-level Decode method is just a convenience that sets
// up the most basic Decoder.
type Decoder struct {
- config *DecoderConfig
+ config *DecoderConfig
+ cachedDecodeHook func(from reflect.Value, to reflect.Value) (interface{}, error)
}
// Metadata contains information about decoding a structure that
@@ -400,6 +406,10 @@ func NewDecoder(config *DecoderConfig) (*Decoder, error) {
config.TagName = "mapstructure"
}
+ if config.SquashTagOption == "" {
+ config.SquashTagOption = "squash"
+ }
+
if config.MatchName == nil {
config.MatchName = strings.EqualFold
}
@@ -407,6 +417,9 @@ func NewDecoder(config *DecoderConfig) (*Decoder, error) {
result := &Decoder{
config: config,
}
+ if config.DecodeHook != nil {
+ result.cachedDecodeHook = cachedDecodeHook(config.DecodeHook)
+ }
return result, nil
}
@@ -414,7 +427,15 @@ func NewDecoder(config *DecoderConfig) (*Decoder, error) {
// Decode decodes the given raw interface to the target pointer specified
// by the configuration.
func (d *Decoder) Decode(input interface{}) error {
- return d.decode("", input, reflect.ValueOf(d.config.Result).Elem())
+ err := d.decode("", input, reflect.ValueOf(d.config.Result).Elem())
+
+ // Retain some of the original behavior when multiple errors ocurr
+ var joinedErr interface{ Unwrap() []error }
+ if errors.As(err, &joinedErr) {
+ return fmt.Errorf("decoding failed due to the following error(s):\n\n%w", err)
+ }
+
+ return err
}
// Decodes an unknown data type into a specific reflection value.
@@ -453,10 +474,10 @@ func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) e
return nil
}
- if d.config.DecodeHook != nil {
+ if d.cachedDecodeHook != nil {
// We have a DecodeHook, so let's pre-process the input.
var err error
- input, err = DecodeHookExec(d.config.DecodeHook, inputVal, outVal)
+ input, err = d.cachedDecodeHook(inputVal, outVal)
if err != nil {
return fmt.Errorf("error decoding '%s': %w", name, err)
}
@@ -478,6 +499,8 @@ func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) e
err = d.decodeUint(name, input, outVal)
case reflect.Float32:
err = d.decodeFloat(name, input, outVal)
+ case reflect.Complex64:
+ err = d.decodeComplex(name, input, outVal)
case reflect.Struct:
err = d.decodeStruct(name, input, outVal)
case reflect.Map:
@@ -796,6 +819,22 @@ func (d *Decoder) decodeFloat(name string, data interface{}, val reflect.Value)
return nil
}
+func (d *Decoder) decodeComplex(name string, data interface{}, val reflect.Value) error {
+ dataVal := reflect.Indirect(reflect.ValueOf(data))
+ dataKind := getKind(dataVal)
+
+ switch {
+ case dataKind == reflect.Complex64:
+ val.SetComplex(dataVal.Complex())
+ default:
+ return fmt.Errorf(
+ "'%s' expected type '%s', got unconvertible type '%s', value: '%v'",
+ name, val.Type(), dataVal.Type(), data)
+ }
+
+ return nil
+}
+
func (d *Decoder) decodeMap(name string, data interface{}, val reflect.Value) error {
valType := val.Type()
valKeyType := valType.Key()
@@ -863,7 +902,7 @@ func (d *Decoder) decodeMapFromMap(name string, dataVal reflect.Value, val refle
valElemType := valType.Elem()
// Accumulate errors
- errors := make([]string, 0)
+ var errs []error
// If the input data is empty, then we just match what the input data is.
if dataVal.Len() == 0 {
@@ -885,7 +924,7 @@ func (d *Decoder) decodeMapFromMap(name string, dataVal reflect.Value, val refle
// First decode the key into the proper type
currentKey := reflect.Indirect(reflect.New(valKeyType))
if err := d.decode(fieldName, k.Interface(), currentKey); err != nil {
- errors = appendErrors(errors, err)
+ errs = append(errs, err)
continue
}
@@ -893,7 +932,7 @@ func (d *Decoder) decodeMapFromMap(name string, dataVal reflect.Value, val refle
v := dataVal.MapIndex(k).Interface()
currentVal := reflect.Indirect(reflect.New(valElemType))
if err := d.decode(fieldName, v, currentVal); err != nil {
- errors = appendErrors(errors, err)
+ errs = append(errs, err)
continue
}
@@ -903,12 +942,7 @@ func (d *Decoder) decodeMapFromMap(name string, dataVal reflect.Value, val refle
// Set the built up map to the value
val.Set(valMap)
- // If we had errors, return those
- if len(errors) > 0 {
- return &Error{errors}
- }
-
- return nil
+ return errors.Join(errs...)
}
func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val reflect.Value, valMap reflect.Value) error {
@@ -951,7 +985,7 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
}
// If "squash" is specified in the tag, we squash the field down.
- squash = squash || strings.Index(tagValue[index+1:], "squash") != -1
+ squash = squash || strings.Contains(tagValue[index+1:], d.config.SquashTagOption)
if squash {
// When squashing, the embedded type can be a pointer to a struct.
if v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct {
@@ -1146,7 +1180,7 @@ func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value)
}
// Accumulate any errors
- errors := make([]string, 0)
+ var errs []error
for i := 0; i < dataVal.Len(); i++ {
currentData := dataVal.Index(i).Interface()
@@ -1157,19 +1191,14 @@ func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value)
fieldName := name + "[" + strconv.Itoa(i) + "]"
if err := d.decode(fieldName, currentData, currentField); err != nil {
- errors = appendErrors(errors, err)
+ errs = append(errs, err)
}
}
// Finally, set the value to the slice we built up
val.Set(valSlice)
- // If there were errors, we return those
- if len(errors) > 0 {
- return &Error{errors}
- }
-
- return nil
+ return errors.Join(errs...)
}
func (d *Decoder) decodeArray(name string, data interface{}, val reflect.Value) error {
@@ -1215,7 +1244,7 @@ func (d *Decoder) decodeArray(name string, data interface{}, val reflect.Value)
}
// Accumulate any errors
- errors := make([]string, 0)
+ var errs []error
for i := 0; i < dataVal.Len(); i++ {
currentData := dataVal.Index(i).Interface()
@@ -1223,19 +1252,14 @@ func (d *Decoder) decodeArray(name string, data interface{}, val reflect.Value)
fieldName := name + "[" + strconv.Itoa(i) + "]"
if err := d.decode(fieldName, currentData, currentField); err != nil {
- errors = appendErrors(errors, err)
+ errs = append(errs, err)
}
}
// Finally, set the value to the array we built up
val.Set(valArray)
- // If there were errors, we return those
- if len(errors) > 0 {
- return &Error{errors}
- }
-
- return nil
+ return errors.Join(errs...)
}
func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value) error {
@@ -1297,7 +1321,8 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
}
targetValKeysUnused := make(map[interface{}]struct{})
- errors := make([]string, 0)
+
+ var errs []error
// This slice will keep track of all the structs we'll be decoding.
// There can be more than one struct if there are embedded structs
@@ -1338,7 +1363,7 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
// We always parse the tags cause we're looking for other tags too
tagParts := strings.Split(fieldType.Tag.Get(d.config.TagName), ",")
for _, tag := range tagParts[1:] {
- if tag == "squash" {
+ if tag == d.config.SquashTagOption {
squash = true
break
}
@@ -1350,11 +1375,15 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
}
if squash {
- if fieldVal.Kind() != reflect.Struct {
- errors = appendErrors(errors,
- fmt.Errorf("%s: unsupported type for squash: %s", fieldType.Name, fieldVal.Kind()))
- } else {
+ switch fieldVal.Kind() {
+ case reflect.Struct:
structs = append(structs, fieldVal)
+ case reflect.Interface:
+ if !fieldVal.IsNil() {
+ structs = append(structs, fieldVal.Elem().Elem())
+ }
+ default:
+ errs = append(errs, fmt.Errorf("%s: unsupported type for squash: %s", fieldType.Name, fieldVal.Kind()))
}
continue
}
@@ -1431,7 +1460,7 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
}
if err := d.decode(fieldName, rawMapVal.Interface(), fieldValue); err != nil {
- errors = appendErrors(errors, err)
+ errs = append(errs, err)
}
}
@@ -1446,7 +1475,7 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
// Decode it as-if we were just decoding this map onto our map.
if err := d.decodeMap(name, remain, remainField.val); err != nil {
- errors = appendErrors(errors, err)
+ errs = append(errs, err)
}
// Set the map to nil so we have none so that the next check will
@@ -1462,7 +1491,7 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
sort.Strings(keys)
err := fmt.Errorf("'%s' has invalid keys: %s", name, strings.Join(keys, ", "))
- errors = appendErrors(errors, err)
+ errs = append(errs, err)
}
if d.config.ErrorUnset && len(targetValKeysUnused) > 0 {
@@ -1473,11 +1502,11 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
sort.Strings(keys)
err := fmt.Errorf("'%s' has unset fields: %s", name, strings.Join(keys, ", "))
- errors = appendErrors(errors, err)
+ errs = append(errs, err)
}
- if len(errors) > 0 {
- return &Error{errors}
+ if err := errors.Join(errs...); err != nil {
+ return err
}
// Add the unused keys to the list of unused keys if we're tracking metadata
@@ -1531,6 +1560,8 @@ func getKind(val reflect.Value) reflect.Kind {
return reflect.Uint
case kind >= reflect.Float32 && kind <= reflect.Float64:
return reflect.Float32
+ case kind >= reflect.Complex64 && kind <= reflect.Complex128:
+ return reflect.Complex64
default:
return kind
}