OSDN Git Service

Hulk did something
[bytom/vapor.git] / vendor / github.com / mitchellh / mapstructure / decode_hooks.go
diff --git a/vendor/github.com/mitchellh/mapstructure/decode_hooks.go b/vendor/github.com/mitchellh/mapstructure/decode_hooks.go
new file mode 100644 (file)
index 0000000..afcfd5e
--- /dev/null
@@ -0,0 +1,152 @@
+package mapstructure
+
+import (
+       "errors"
+       "reflect"
+       "strconv"
+       "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) {
+       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
+// automatically composes multiple DecodeHookFuncs.
+//
+// The composed funcs are called in order, with the result of the
+// previous transformation.
+func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc {
+       return func(
+               f reflect.Type,
+               t reflect.Type,
+               data interface{}) (interface{}, error) {
+               var err error
+               for _, f1 := range fs {
+                       data, err = DecodeHookExec(f1, f, t, data)
+                       if err != nil {
+                               return nil, err
+                       }
+
+                       // Modify the from kind to be correct with the new data
+                       f = nil
+                       if val := reflect.ValueOf(data); val.IsValid() {
+                               f = val.Type()
+                       }
+               }
+
+               return data, nil
+       }
+}
+
+// StringToSliceHookFunc returns a DecodeHookFunc that converts
+// string to []string by splitting on the given sep.
+func StringToSliceHookFunc(sep string) DecodeHookFunc {
+       return func(
+               f reflect.Kind,
+               t reflect.Kind,
+               data interface{}) (interface{}, error) {
+               if f != reflect.String || t != reflect.Slice {
+                       return data, nil
+               }
+
+               raw := data.(string)
+               if raw == "" {
+                       return []string{}, nil
+               }
+
+               return strings.Split(raw, sep), nil
+       }
+}
+
+// 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))
+       }
+}
+
+// WeaklyTypedHook is a DecodeHookFunc which adds support for weak typing to
+// the decoder.
+//
+// Note that this is significantly different from the WeaklyTypedInput option
+// of the DecoderConfig.
+func WeaklyTypedHook(
+       f reflect.Kind,
+       t reflect.Kind,
+       data interface{}) (interface{}, error) {
+       dataVal := reflect.ValueOf(data)
+       switch t {
+       case reflect.String:
+               switch f {
+               case reflect.Bool:
+                       if dataVal.Bool() {
+                               return "1", nil
+                       }
+                       return "0", nil
+               case reflect.Float32:
+                       return strconv.FormatFloat(dataVal.Float(), 'f', -1, 64), nil
+               case reflect.Int:
+                       return strconv.FormatInt(dataVal.Int(), 10), nil
+               case reflect.Slice:
+                       dataType := dataVal.Type()
+                       elemKind := dataType.Elem().Kind()
+                       if elemKind == reflect.Uint8 {
+                               return string(dataVal.Interface().([]uint8)), nil
+                       }
+               case reflect.Uint:
+                       return strconv.FormatUint(dataVal.Uint(), 10), nil
+               }
+       }
+
+       return data, nil
+}