vendor/github.com/mitchellh/mapstructure/decode_hooks.go
changeset 256 6d9efbef00a9
parent 251 1c52a0eeb952
child 260 445e01aede7e
equal deleted inserted replaced
255:4f153a23adab 256:6d9efbef00a9
     1 package mapstructure
     1 package mapstructure
     2 
     2 
     3 import (
     3 import (
       
     4 	"encoding"
     4 	"errors"
     5 	"errors"
     5 	"fmt"
     6 	"fmt"
     6 	"net"
     7 	"net"
     7 	"reflect"
     8 	"reflect"
     8 	"strconv"
     9 	"strconv"
    14 // it into the proper DecodeHookFunc type, such as DecodeHookFuncType.
    15 // it into the proper DecodeHookFunc type, such as DecodeHookFuncType.
    15 func typedDecodeHook(h DecodeHookFunc) DecodeHookFunc {
    16 func typedDecodeHook(h DecodeHookFunc) DecodeHookFunc {
    16 	// Create variables here so we can reference them with the reflect pkg
    17 	// Create variables here so we can reference them with the reflect pkg
    17 	var f1 DecodeHookFuncType
    18 	var f1 DecodeHookFuncType
    18 	var f2 DecodeHookFuncKind
    19 	var f2 DecodeHookFuncKind
       
    20 	var f3 DecodeHookFuncValue
    19 
    21 
    20 	// Fill in the variables into this interface and the rest is done
    22 	// Fill in the variables into this interface and the rest is done
    21 	// automatically using the reflect package.
    23 	// automatically using the reflect package.
    22 	potential := []interface{}{f1, f2}
    24 	potential := []interface{}{f1, f2, f3}
    23 
    25 
    24 	v := reflect.ValueOf(h)
    26 	v := reflect.ValueOf(h)
    25 	vt := v.Type()
    27 	vt := v.Type()
    26 	for _, raw := range potential {
    28 	for _, raw := range potential {
    27 		pt := reflect.ValueOf(raw).Type()
    29 		pt := reflect.ValueOf(raw).Type()
    36 // DecodeHookExec executes the given decode hook. This should be used
    38 // DecodeHookExec executes the given decode hook. This should be used
    37 // since it'll naturally degrade to the older backwards compatible DecodeHookFunc
    39 // since it'll naturally degrade to the older backwards compatible DecodeHookFunc
    38 // that took reflect.Kind instead of reflect.Type.
    40 // that took reflect.Kind instead of reflect.Type.
    39 func DecodeHookExec(
    41 func DecodeHookExec(
    40 	raw DecodeHookFunc,
    42 	raw DecodeHookFunc,
    41 	from reflect.Type, to reflect.Type,
    43 	from reflect.Value, to reflect.Value) (interface{}, error) {
    42 	data interface{}) (interface{}, error) {
    44 
    43 	switch f := typedDecodeHook(raw).(type) {
    45 	switch f := typedDecodeHook(raw).(type) {
    44 	case DecodeHookFuncType:
    46 	case DecodeHookFuncType:
    45 		return f(from, to, data)
    47 		return f(from.Type(), to.Type(), from.Interface())
    46 	case DecodeHookFuncKind:
    48 	case DecodeHookFuncKind:
    47 		return f(from.Kind(), to.Kind(), data)
    49 		return f(from.Kind(), to.Kind(), from.Interface())
       
    50 	case DecodeHookFuncValue:
       
    51 		return f(from, to)
    48 	default:
    52 	default:
    49 		return nil, errors.New("invalid decode hook signature")
    53 		return nil, errors.New("invalid decode hook signature")
    50 	}
    54 	}
    51 }
    55 }
    52 
    56 
    54 // automatically composes multiple DecodeHookFuncs.
    58 // automatically composes multiple DecodeHookFuncs.
    55 //
    59 //
    56 // The composed funcs are called in order, with the result of the
    60 // The composed funcs are called in order, with the result of the
    57 // previous transformation.
    61 // previous transformation.
    58 func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc {
    62 func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc {
    59 	return func(
    63 	return func(f reflect.Value, t reflect.Value) (interface{}, error) {
    60 		f reflect.Type,
       
    61 		t reflect.Type,
       
    62 		data interface{}) (interface{}, error) {
       
    63 		var err error
    64 		var err error
       
    65 		var data interface{}
       
    66 		newFrom := f
    64 		for _, f1 := range fs {
    67 		for _, f1 := range fs {
    65 			data, err = DecodeHookExec(f1, f, t, data)
    68 			data, err = DecodeHookExec(f1, newFrom, t)
    66 			if err != nil {
    69 			if err != nil {
    67 				return nil, err
    70 				return nil, err
    68 			}
    71 			}
    69 
    72 			newFrom = reflect.ValueOf(data)
    70 			// Modify the from kind to be correct with the new data
       
    71 			f = nil
       
    72 			if val := reflect.ValueOf(data); val.IsValid() {
       
    73 				f = val.Type()
       
    74 			}
       
    75 		}
    73 		}
    76 
    74 
    77 		return data, nil
    75 		return data, nil
    78 	}
    76 	}
    79 }
    77 }
   213 		}
   211 		}
   214 	}
   212 	}
   215 
   213 
   216 	return data, nil
   214 	return data, nil
   217 }
   215 }
       
   216 
       
   217 func RecursiveStructToMapHookFunc() DecodeHookFunc {
       
   218 	return func(f reflect.Value, t reflect.Value) (interface{}, error) {
       
   219 		if f.Kind() != reflect.Struct {
       
   220 			return f.Interface(), nil
       
   221 		}
       
   222 
       
   223 		var i interface{} = struct{}{}
       
   224 		if t.Type() != reflect.TypeOf(&i).Elem() {
       
   225 			return f.Interface(), nil
       
   226 		}
       
   227 
       
   228 		m := make(map[string]interface{})
       
   229 		t.Set(reflect.ValueOf(m))
       
   230 
       
   231 		return f.Interface(), nil
       
   232 	}
       
   233 }
       
   234 
       
   235 // TextUnmarshallerHookFunc returns a DecodeHookFunc that applies
       
   236 // strings to the UnmarshalText function, when the target type
       
   237 // implements the encoding.TextUnmarshaler interface
       
   238 func TextUnmarshallerHookFunc() DecodeHookFuncType {
       
   239 	return func(
       
   240 		f reflect.Type,
       
   241 		t reflect.Type,
       
   242 		data interface{}) (interface{}, error) {
       
   243 		if f.Kind() != reflect.String {
       
   244 			return data, nil
       
   245 		}
       
   246 		result := reflect.New(t).Interface()
       
   247 		unmarshaller, ok := result.(encoding.TextUnmarshaler)
       
   248 		if !ok {
       
   249 			return data, nil
       
   250 		}
       
   251 		if err := unmarshaller.UnmarshalText([]byte(data.(string))); err != nil {
       
   252 			return nil, err
       
   253 		}
       
   254 		return result, nil
       
   255 	}
       
   256 }