@@ -36,6 +36,30 @@ func typedDecodeHook(h DecodeHookFunc) DecodeHookFunc {
36
36
return nil
37
37
}
38
38
39
+ // cachedDecodeHook takes a raw DecodeHookFunc (an interface{}) and turns
40
+ // it into a closure to be used directly
41
+ // if the type fails to convert we return a closure always erroring to keep the previous behaviour
42
+ func cachedDecodeHook (raw DecodeHookFunc ) func (from reflect.Value , to reflect.Value ) (interface {}, error ) {
43
+ switch f := typedDecodeHook (raw ).(type ) {
44
+ case DecodeHookFuncType :
45
+ return func (from reflect.Value , to reflect.Value ) (interface {}, error ) {
46
+ return f (from .Type (), to .Type (), from .Interface ())
47
+ }
48
+ case DecodeHookFuncKind :
49
+ return func (from reflect.Value , to reflect.Value ) (interface {}, error ) {
50
+ return f (from .Kind (), to .Kind (), from .Interface ())
51
+ }
52
+ case DecodeHookFuncValue :
53
+ return func (from reflect.Value , to reflect.Value ) (interface {}, error ) {
54
+ return f (from , to )
55
+ }
56
+ default :
57
+ return func (from reflect.Value , to reflect.Value ) (interface {}, error ) {
58
+ return nil , errors .New ("invalid decode hook signature" )
59
+ }
60
+ }
61
+ }
62
+
39
63
// DecodeHookExec executes the given decode hook. This should be used
40
64
// since it'll naturally degrade to the older backwards compatible DecodeHookFunc
41
65
// that took reflect.Kind instead of reflect.Type.
@@ -61,13 +85,17 @@ func DecodeHookExec(
61
85
// The composed funcs are called in order, with the result of the
62
86
// previous transformation.
63
87
func ComposeDecodeHookFunc (fs ... DecodeHookFunc ) DecodeHookFunc {
88
+ cached := make ([]func (from reflect.Value , to reflect.Value ) (interface {}, error ), 0 , len (fs ))
89
+ for _ , f := range fs {
90
+ cached = append (cached , cachedDecodeHook (f ))
91
+ }
64
92
return func (f reflect.Value , t reflect.Value ) (interface {}, error ) {
65
93
var err error
66
94
data := f .Interface ()
67
95
68
96
newFrom := f
69
- for _ , f1 := range fs {
70
- data , err = DecodeHookExec ( f1 , newFrom , t )
97
+ for _ , c := range cached {
98
+ data , err = c ( newFrom , t )
71
99
if err != nil {
72
100
return nil , err
73
101
}
@@ -81,13 +109,17 @@ func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc {
81
109
// OrComposeDecodeHookFunc executes all input hook functions until one of them returns no error. In that case its value is returned.
82
110
// If all hooks return an error, OrComposeDecodeHookFunc returns an error concatenating all error messages.
83
111
func OrComposeDecodeHookFunc (ff ... DecodeHookFunc ) DecodeHookFunc {
112
+ cached := make ([]func (from reflect.Value , to reflect.Value ) (interface {}, error ), 0 , len (ff ))
113
+ for _ , f := range ff {
114
+ cached = append (cached , cachedDecodeHook (f ))
115
+ }
84
116
return func (a , b reflect.Value ) (interface {}, error ) {
85
117
var allErrs string
86
118
var out interface {}
87
119
var err error
88
120
89
- for _ , f := range ff {
90
- out , err = DecodeHookExec ( f , a , b )
121
+ for _ , c := range cached {
122
+ out , err = c ( a , b )
91
123
if err != nil {
92
124
allErrs += err .Error () + "\n "
93
125
continue
0 commit comments