http urls monitor.

decode_hooks.go 4.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. package mapstructure
  2. import (
  3. "errors"
  4. "reflect"
  5. "strconv"
  6. "strings"
  7. "time"
  8. )
  9. // typedDecodeHook takes a raw DecodeHookFunc (an interface{}) and turns
  10. // it into the proper DecodeHookFunc type, such as DecodeHookFuncType.
  11. func typedDecodeHook(h DecodeHookFunc) DecodeHookFunc {
  12. // Create variables here so we can reference them with the reflect pkg
  13. var f1 DecodeHookFuncType
  14. var f2 DecodeHookFuncKind
  15. // Fill in the variables into this interface and the rest is done
  16. // automatically using the reflect package.
  17. potential := []interface{}{f1, f2}
  18. v := reflect.ValueOf(h)
  19. vt := v.Type()
  20. for _, raw := range potential {
  21. pt := reflect.ValueOf(raw).Type()
  22. if vt.ConvertibleTo(pt) {
  23. return v.Convert(pt).Interface()
  24. }
  25. }
  26. return nil
  27. }
  28. // DecodeHookExec executes the given decode hook. This should be used
  29. // since it'll naturally degrade to the older backwards compatible DecodeHookFunc
  30. // that took reflect.Kind instead of reflect.Type.
  31. func DecodeHookExec(
  32. raw DecodeHookFunc,
  33. from reflect.Type, to reflect.Type,
  34. data interface{}) (interface{}, error) {
  35. switch f := typedDecodeHook(raw).(type) {
  36. case DecodeHookFuncType:
  37. return f(from, to, data)
  38. case DecodeHookFuncKind:
  39. return f(from.Kind(), to.Kind(), data)
  40. default:
  41. return nil, errors.New("invalid decode hook signature")
  42. }
  43. }
  44. // ComposeDecodeHookFunc creates a single DecodeHookFunc that
  45. // automatically composes multiple DecodeHookFuncs.
  46. //
  47. // The composed funcs are called in order, with the result of the
  48. // previous transformation.
  49. func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc {
  50. return func(
  51. f reflect.Type,
  52. t reflect.Type,
  53. data interface{}) (interface{}, error) {
  54. var err error
  55. for _, f1 := range fs {
  56. data, err = DecodeHookExec(f1, f, t, data)
  57. if err != nil {
  58. return nil, err
  59. }
  60. // Modify the from kind to be correct with the new data
  61. f = nil
  62. if val := reflect.ValueOf(data); val.IsValid() {
  63. f = val.Type()
  64. }
  65. }
  66. return data, nil
  67. }
  68. }
  69. // StringToSliceHookFunc returns a DecodeHookFunc that converts
  70. // string to []string by splitting on the given sep.
  71. func StringToSliceHookFunc(sep string) DecodeHookFunc {
  72. return func(
  73. f reflect.Kind,
  74. t reflect.Kind,
  75. data interface{}) (interface{}, error) {
  76. if f != reflect.String || t != reflect.Slice {
  77. return data, nil
  78. }
  79. raw := data.(string)
  80. if raw == "" {
  81. return []string{}, nil
  82. }
  83. return strings.Split(raw, sep), nil
  84. }
  85. }
  86. // StringToTimeDurationHookFunc returns a DecodeHookFunc that converts
  87. // strings to time.Duration.
  88. func StringToTimeDurationHookFunc() DecodeHookFunc {
  89. return func(
  90. f reflect.Type,
  91. t reflect.Type,
  92. data interface{}) (interface{}, error) {
  93. if f.Kind() != reflect.String {
  94. return data, nil
  95. }
  96. if t != reflect.TypeOf(time.Duration(5)) {
  97. return data, nil
  98. }
  99. // Convert it by parsing
  100. return time.ParseDuration(data.(string))
  101. }
  102. }
  103. // StringToTimeHookFunc returns a DecodeHookFunc that converts
  104. // strings to time.Time.
  105. func StringToTimeHookFunc(layout string) DecodeHookFunc {
  106. return func(
  107. f reflect.Type,
  108. t reflect.Type,
  109. data interface{}) (interface{}, error) {
  110. if f.Kind() != reflect.String {
  111. return data, nil
  112. }
  113. if t != reflect.TypeOf(time.Time{}) {
  114. return data, nil
  115. }
  116. // Convert it by parsing
  117. return time.Parse(layout, data.(string))
  118. }
  119. }
  120. // WeaklyTypedHook is a DecodeHookFunc which adds support for weak typing to
  121. // the decoder.
  122. //
  123. // Note that this is significantly different from the WeaklyTypedInput option
  124. // of the DecoderConfig.
  125. func WeaklyTypedHook(
  126. f reflect.Kind,
  127. t reflect.Kind,
  128. data interface{}) (interface{}, error) {
  129. dataVal := reflect.ValueOf(data)
  130. switch t {
  131. case reflect.String:
  132. switch f {
  133. case reflect.Bool:
  134. if dataVal.Bool() {
  135. return "1", nil
  136. }
  137. return "0", nil
  138. case reflect.Float32:
  139. return strconv.FormatFloat(dataVal.Float(), 'f', -1, 64), nil
  140. case reflect.Int:
  141. return strconv.FormatInt(dataVal.Int(), 10), nil
  142. case reflect.Slice:
  143. dataType := dataVal.Type()
  144. elemKind := dataType.Elem().Kind()
  145. if elemKind == reflect.Uint8 {
  146. return string(dataVal.Interface().([]uint8)), nil
  147. }
  148. case reflect.Uint:
  149. return strconv.FormatUint(dataVal.Uint(), 10), nil
  150. }
  151. }
  152. return data, nil
  153. }